【问题标题】:setTimeout in memory game记忆游戏中的setTimeout
【发布时间】:2020-03-14 06:32:06
【问题描述】:

我正在用 javascript 制作一个记忆游戏,并将其放在我的网页上。我有 3 个标记为 1、2 和 3 的按钮,它们应该按一定的顺序变成绿色然后再变成白色。顺序是随机的,每回合加1。然后玩家应该以正确的顺序点击按钮。问题是,当我将按钮颜色更改为绿色时,不是每个按钮按正确的顺序变为绿色然后再次变为白色,而是按钮一次全部变为绿色。这是javascript逻辑:

function lightUp() {
  var arrayOrder = gameOrder.split("");
  for(let i = 0; i < arrayOrder.length; i++) {
    document.getElementById("but" + arrayOrder[i]).style.backgroundColor = "green";
    setTimeout(function() {
      document.getElementById("but" + arrayOrder[i]).style.backgroundColor = "white";
    }, 1000);
  }
}

gameOrder是一个数字顺序的字符串(例如“12331232123”)

我认为游戏无法运行是因为 setTimeout 的工作方式,我相信它会在后台暂停并允许 for 循环继续运行而不是暂停整个函数一秒钟(这就是我正在尝试)。

我希望每个按钮在下一个按钮改变颜色之前打开然后关闭。因此,如果顺序是 1 2 3,我希望按钮 1 变为绿色然后变为白色,然后按钮 2 变为绿色然后变为白色,最后按钮 3 变为绿色然后变为白色。

【问题讨论】:

  • 因为它们都同时运行设置为绿色并且它们都在 1000 毫秒时关闭,所以它们不是同步的。
  • 我怎样才能修复代码,让一个打开然后关闭,然后再下一个?
  • 建立一个队列类型的设置而不是一个循环。
  • 您可以使用 for 循环逐步设置超时

标签: javascript


【解决方案1】:

正如 espacarello 所指出的,JS 不是同步的。您可以使函数异步并等待setTimeout

这是我使用 JS 为事物“动画化”的首选方式:

async function lightUp() {
  const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
  for (const i of gameOrder.split('')) {
    const el = document.getElementById(`but${i}`);
    el.style.backgroundColor = 'green';
    await sleep(1000);
    el.style.backgroundColor = 'white';
  }
}

这将保持简单和优雅,而不会因大量回调、递归或嵌套 setTimeouts 而弄乱您的代码。它仍然是一个功能。


编辑: 请务必注意,IE 不支持 Promises 或箭头函数语法。请参阅其他两个答案以获得更广泛的支持。

【讨论】:

  • 希望 OP 意识到这个解决方案不适用于所有浏览器。
  • @epascarello 是的!重要的是要注意。其他两个答案将以失去一些简洁性为代价提供更广泛的支持。这在 IE 中根本不起作用(不支持箭头函数和承诺 both)。
【解决方案2】:

您的代码的问题是 for 循环一次运行,没有延迟。您对其进行编码认为间隔将导致循环等待直到它被执行。问题是,无需等待即可运行。

使用队列类型的系统,您可以在其中运行该步骤,完成后,您将运行下一个步骤,直到您做完所有事情。

var steps = [1,2,3,2,1,3,1]
var delay = 1000
var step = 0

function next () {
  var button = document.getElementById('btn' + steps[step])
  button.classList.add("on")
  window.setTimeout( function () {
    button.classList.remove("on")
    step++
    if(step<steps.length) next()
  }, delay)  
}

next()
.on {
  background-color: green;
}
<button id="btn1">One</button>
<button id="btn2">Two</button>
<button id="btn3">Three</button>

【讨论】:

    【解决方案3】:

    您可以按照以下方式进行操作...

    function lightUp() {
      var arrayOrder = gameOrder.split("");
      for (let i = 0; i < arrayOrder.length; i++) {
        (function(i) {
           setTimeout(function() {
             document.getElementById("but" + arrayOrder[i]).style.backgroundColor = "green";
           }, 1000 * i - 1000);
          setTimeout(function() {
            document.getElementById("but" + arrayOrder[i]).style.backgroundColor = "white";
          }, 1000 * i); // schedules excution increasingly for each iteration
        })(i);
      }
    }
    

    要了解更多关于它的工作原理,请参考this answer

    【讨论】:

    • 仍然不是 OP 想要的。它们都是绿色的。
    • 现在应该没问题了:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-24
    • 2012-05-05
    相关资源
    最近更新 更多