【问题标题】:Why falling box in HTML & JavaScript using setInterval doesn't work as expected?为什么使用 setInterval 的 HTML 和 JavaScript 中的落框不能按预期工作?
【发布时间】:2022-01-24 20:48:38
【问题描述】:

https://codepen.io/skinaqua123/pen/WNZZgEy

<div id="container">
  <div id="box"></div>
</div>

#container {
  background-color: black;
  width: 800px;
  height: 500px;
  position: relative;
}

#box {
  width: 50px;
  height: 50px;
  background-color: yellow;
  position: absolute;
  top: 0px;
  transition: top 0.5s ease-out 0s;
}

html {
  height: 100%;
  max-height: 100%;
}

const box = document.querySelector("#box");
console.log(box.offsetTop);
const fallingMovement = setInterval(() => {
  box.style.top = box.offsetTop + 50 + "px";
  if (box.offsetTop >= 500 - 50 - 50) {
    clearInterval(fallingMovement);
  }
}, 1000);

您好,我正在为我的 html 游戏测试一些代码。我想要一个盒子掉下来,但不要超出包装 div。

我的包装 div(容器)的高度是 500px,我的盒子是 50px。我认为它应该在顶部为 450px (500-50) 时停止。

但实际上,它仍然比应有的多 50 像素。当我将其更改为 400 时,它可以正常工作。

为什么会这样?即使我调用了clearInterval,我给setInterval 的函数是否会再次执行?

谢谢

【问题讨论】:

    标签: javascript html css setinterval


    【解决方案1】:

    你必须在调用clearInterval后更改box.style.top

    const box = document.querySelector("#box");
    const fallingMovement = setInterval(() => {
      console.log('run interval --------')
      console.log('current offsetTop', box.offsetTop)
      console.log('future offsetTop', box.offsetTop + 50)
    
      if (box.offsetTop >= 500 - 50) {
        clearInterval(fallingMovement);
        return;
      }
      
      box.style.top = box.offsetTop + 50 + "px";
    }, 1000);
    

    【讨论】:

      【解决方案2】:

      间隔回调执行和渲染结果之间存在时间延迟。您可以通过在更改 box.style.top 和超时后立即比较 box.offsetTop 结果来看到这一点:

      const fallingMovement = setInterval(() => {
        box.style.top = box.offsetTop + 50 + "px";
        if (box.offsetTop >= 500 - 50 - 50) {
          clearInterval(fallingMovement);
          console.log(box.offsetTop); // Will print 400.
          setTimeout(() => {console.log(box.offsetTop);}, 500); // Will print 450.
        }
      }, 1000);
      

      要解决此问题,您只需在更新之前而不是之后执行检查:

      const fallingMovement = setInterval(() => {
        if (box.offsetTop >= 500 - 50 - 50) {
          clearInterval(fallingMovement);
          return;
        }
      
        box.style.top = box.offsetTop + 50 + "px";
      }, 1000);
      

      或者,您可以考虑这种延迟的偏移更新:

      const fallingMovement = setInterval(() => {
        box.style.top = box.offsetTop + 50 + "px";
        if (box.offsetTop + 50 >= 500 - 50 -50) {
          clearInterval(fallingMovement);
        }
      }, 1000);
      

      【讨论】:

        【解决方案3】:

        这其实是一个很简单但很容易忽视的问题。

        您的测试在移动调用的后期进行。在测试它是否应该移动之前,您首先调用移动。

        你可以通过改变你的逻辑来修复它。首先检查它是否应该移动,然后调用移动。例如:

        const fallingMovement = setInterval(() => {
          if (box.offsetTop < 500 - 50) {
            box.style.top = box.offsetTop + 50 + "px";
          } else {
            clearInterval(fallingMovement);
          }
        }, 1000);
        

        所以,首先我要检查从盒子顶部到包装器顶部的距离是否小于 450,然后我开始行动。如果是 450 或更多,则间隔将被清除,移动将不会被调用。这样,它将按预期工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-05-30
          • 2020-03-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多