setInterval() 添加 class 然后删除 class 相同的时间

setInterval() to add class then remove class for same amount of time

我正在尝试做一个简单的 'Simon Game'。我目前一直在尝试将 class 'on' 添加到 div 一秒钟,然后在相同的时间内删除 class。

所以我有四个 div 闪烁,具体取决于数字序列,例如[0, 1, 2, 3]。这将闪烁 div[0] 一秒钟,然后关闭一秒钟,然后移动到 div[1],打开和关闭,依此类推。

这是我的函数

/**
 * sequence => array [0, 1, 2, 3]
 * speed    => int 1000 (one second)
 */
playSequence: function(sequence, speed){
    var self = this;

    // removes class 'on'
    view.turnOffPads();
    setTimeout(function(){
        // adds the 'on' class to a specific div
        view.lightUpPad(model.startupSequence[model.count]);
    }, speed / 2);

    setTimeout(function(){
        model.count++; // keeps track of the iterations
        if (model.count < sequence.length) { // if we are still iterating
            self.playSequence(sequence, speed); // light up the next div
        } else {
            model.count = 0; // set back to zero
        }
    }, speed);
},

这个问题是我同时使用了两个 setTimeout 函数,虽然它有效,但我想知道是否有更好的方法。如果你看的话,我在我的模型对象中使用了一个计数变量来跟踪迭代。

这是我到目前为止的完整 javascript 应用...

$(function(){

    var model = {
        on: false,
        strictMode: false,
        startupSequence: [0, 1, 2, 3, 3, 3, 2, 1, 0, 3, 2, 1, 0, 2, 1, 3],
        score: 0,
        sequence: [],
        count: 0,
    }

    var controller = {
        init: function(){
            view.cacheDOM();
            view.bindEvents();
        },
        getSequence: function(){
            // get a random number from one to 4
            var random = Math.floor(Math.random() * 4);
            // push it to the sequence array
            model.sequence.push(random);
            console.log(model.sequence);
            // play it
            this.playSequence(model.sequence);
        },

        /**
         * sequence => array [0, 1, 2, 3]
         * speed    => int 1000 (one second)
         */
        playSequence: function(sequence, speed){
            console.log(sequence.length);
            var self = this;

            view.turnOffPads();
            setTimeout(function(){
                view.lightUpPad(model.startupSequence[model.count]);
            }, speed / 2);

            setTimeout(function(){
                model.count++;
                if (model.count < sequence.length) {
                    self.playSequence(sequence, speed);
                } else {
                    model.count = 0;
                }
            }, speed);
            // view.turnOffPads();
        },
    }

    var view = {
        cacheDOM: function(){
            this.$round  = $('#round');
            this.$start  = $('#start');
            this.$strict = $('#strict');
            this.$pad    = $('.pad');

            this.$padArray = document.getElementsByClassName('pad');
        },
        bindEvents: function(){
            this.$start .change(this.start.bind(this));
            this.$strict.change(this.setStrictMode.bind(this));
        },
        start: function(){
            // turn on pads
            if (model.on) {
                this.$pad.removeClass('on');
                this.$round.text('--');
                model.on = false;
                // reset everything
            } else {
                this.$round.text(model.score);
                model.on = true;
                controller.playSequence(model.startupSequence, 100)
                // controller.getSequence();
            }
        },
        lightUpPad: function(i){
            $(this.$padArray[i]).addClass('on');
        },
        turnOffPads: function(){
            this.$pad.removeClass('on');
        },
        setStrictMode: function(){
            if (model.strictMode) {
                model.strictMode = false;
            } else {
                model.strictMode = true;
            }
        }
    }

    controller.init();
});

是否有更简洁的方法来添加 class,然后删除 class?

TLDR ;)

您需要做的就是使用 setInterval()setTimeout() 并在回调函数中使用 element.classList.toggle() 添加或删除一个class 来自元素。

If/when你想要停止闪烁,只需使用clearTimeout()clearInterval()

这是一个例子:

var d = document.getElementById("test");
var b = document.querySelector("button");

b.addEventListener("click", function(){
  // Cancel the timer
  clearTimeout(timer);
});

// Assign the timer's ID to a variable so that
// you can stop it later
var timer = setInterval(function(){
  // Toggle the use of the lightUp class
  test.classList.toggle("lightUp");
},1000);
#test {
  width:100px;
  height:100px;
  background-color:blue;  /* <-- blue will be the default color */
}

#test.lightUp {
  background-color:yellow;
}
<div id="test"></div>
<button>Stop Blinking</button>

我认为您可以将按钮列表变成一系列命令。然后你可以使用单个 setInterval 来播放命令,直到它用完命令。 setInterval 可以使用 1 秒的间隔,如果你想打开和关闭花费同样长的时间,但你也可以将它设置得更快一点以轻松允许不同的持续时间。

下面的示例并非真正基于您的代码,而只是为了说明这个想法。它以按下一组按钮开始(在代码的按钮处)。这些被传递给 getSequence。这将 return 一组命令,在本例中只是要打开的按钮的颜色,因此序列可以是 red,red,red,red,'','','','' 到红灯亮 4 'intervals',然后熄灭 4 'intervals'。通过这种方式,您可以创建复杂的序列,并且通过微小的调整,您甚至可以同时点亮多个按钮。

示例中的间隔设置为 1/10 秒。每种颜色播放 10 步(= 1 秒),每次暂停播放 5 步(= .5 秒)。在控制台中,您会看到要播放的 buttons/colors 基础数组,然后是播放的更精细的序列。

// The play function plays a sequence of commands
function play(sequence) {
  var index = 0;
  var lastid = '';
  var timer = setInterval(function(){
    // End the timer when at the end of the array 
    if (++index >= sequence.length) {
      clearInterval(timer);
      return;
    }
    var newid = sequence[index];
     
    if (lastid != newid) {
      // Something has changed. Check and act.
  
      if (lastid != '') {
      // The last id was set, so lets switch that off first.
        document.getElementById(lastid).classList.remove('on');
        console.log('--- ' + lastid + ' off');
      }
      
      if (newid != '') {
        // New id is set, switch it on
        document.getElementById(newid).classList.add('on');
        console.log('+++ ' + newid + ' on');
      }
      lastid = newid;
    }
  }, 100);
}

// generateSequence takes a list of buttons and converts them to a 
// sequence of color/off commands.
function generateSequence(buttons) {
  var result = [];
  for (var b = 0; b < buttons.length; b++) {
    // 'On' for 10 counts
    for (var i = 0; i < 10; i++) {
      result.push(buttons[b]);
    }
    if (b+1 < buttons.length) {
      // 'Off' for 5 counts
      for (var i = 0; i < 5; i++) {
        result.push('');
      }
    }
  }
  // One 'off' at the end
  result.push('');
  
  return result;
}

var buttons = ['red', 'green', 'red', 'yellow', 'yellow', 'blue'];
console.log(buttons);
var sequence = generateSequence(buttons);
console.log(sequence);
play(sequence);
div.button {
  width: 100px;
  height: 100px;
  opacity: .5;
  display: inline-block;
}
div.button.on {
  opacity: 1;
}
#red {
  background-color: red;
}
#green {
  background-color: green;
}
#yellow {
  background-color: yellow;
}
#blue {
  background-color: blue;
}
<div id="red" class="button"></div>
<div id="green" class="button"></div>
<div id="yellow" class="button"></div>
<div id="blue" class="button"></div>

使用 setInterval 而不是 setTimeout 我创建了四个分区,每个分区闪烁 1 秒。

var i = 0,
    j = 4;

function blink(i) {
  new Promise(function(resolve, reject) {
  x = setTimeout(function() {
    document.querySelectorAll(".post-text")[i].classList.add("myClass");
    resolve("added");
  }, 1000)
  }).then(function(a) {
  new Promise(function(res, rej) {
    setTimeout(function() {
      clearInterval(x);
      document.querySelectorAll(".post-text")[i].classList.remove("myClass");
      res("deleted");
    }, 1000)
  }).then(function(a) {
    i++;
    if (i < j) {
      blink(i);
    } else {
      i = 0;
      blink(i);
    }
  });

  });
}
blink(i);
.myClass {
  background-color:yellow;
}
<div class="post-text">A</div>
<div class="post-text">B</div>
<div class="post-text">C</div>
<div class="post-text">D</div>