requestAnimationFrame 的问题

Issues with requestAnimationFrame

我有一个问题:

document.querySelector('div').addEventListener('mousedown', function(){
        hello = true
        document.body.addEventListener('mousemove', function(e){
            if (hello) {
                document.querySelector('div').style.left = (e.clientX - 12.5) + 'px'
                document.querySelector('div').style.top = (e.clientY - 12.5) + 'px'
            }
        })
        this.addEventListener('mouseup', function(e){
            hello = false
            posY = Math.floor(parseInt(this.style.top))
            function Fall() {
                posY++
                document.querySelector('div').style.top = posY + 'px'
                if (posY != parseInt(window.innerHeight) - 25) requestAnimationFrame(Fall)
            }
            Fall()
        })
    })
body {
  margin:0;
  position:absolute;
  height:100vh;
  width:100vw;
  overflow:hidden
}

div {
  position:absolute;
  height:25px;
  width:25px;
  border:1px #000 solid;
  bottom:0
}
div:hover {
  cursor:pointer;
}
<div></div>

在这段代码中(also on jsFiddle,当我放下 div 时,我希望 div 掉落,并停在地面上。

第一次成功。但是, requestAnimationFrame 更快,就像第一个没有完成......?在那之后,div 并没有停在地面上:(

我必须使用 setInterval 而不是 requestAnimationFrame 吗?

问题是您要添加 mouseup 处理程序 每次 div 收到 mousedown。您只想执行一次,因此请将其移出 mousedown 处理程序。因此,您在第二次调用时设置动画两次(因为两个处理程序都响应),在第三次调用三次(因为所有三个处理程序都响应)等。并且由于多个处理程序正在更新 poxY,它不会停止不再在地面上了,因为 != 检查失败,除了其中一个。 (请参阅代码段下的更多注释。)

document.querySelector('div').addEventListener('mousedown', function() {
  hello = true
  document.body.addEventListener('mousemove', function(e) {
    if (hello) {
      document.querySelector('div').style.left = (e.clientX - 12.5) + 'px'
      document.querySelector('div').style.top = (e.clientY - 12.5) + 'px'
    }
  })
})
// Moved the below
document.querySelector('div').addEventListener('mouseup', function(e) {
  hello = false
  posY = Math.floor(parseInt(this.style.top))

  function Fall() {
    posY++
    document.querySelector('div').style.top = posY + 'px'
    if (posY != parseInt(window.innerHeight) - 25) requestAnimationFrame(Fall)
  }
  Fall()
})
body {
  margin: 0;
  position: absolute;
  height: 100vh;
  width: 100vw;
  overflow: hidden
}

div {
  position: absolute;
  height: 25px;
  width: 25px;
  border: 1px #000 solid;
  bottom: 0
}

div:hover {
  cursor: pointer;
}
<div class="square"></div>

其他一些观察:

  • 您的代码正在成为 The Horror of Implicit Globals* 的牺牲品——声明您的变量
  • 与其一直重新查询 DOM,不如查询 DOM 以获得 div 一次 ], 并记在一个变量中

* (披露:这是我贫血的小博客上的 post)

只要单击 div(鼠标按下),就会分配另一个侦听器。当你停止点击时,这些监听器都是按顺序执行的,所以在第二次点击时,会有两次循环运行,第三次之后会有三次循环运行,依此类推。您可以只分配一次监听器:

var hello,posY;

document.querySelector('div').addEventListener('mousedown', function(){
  hello = true;
});

document.body.addEventListener('mousemove', function(e){
    if (hello) {
        document.querySelector('div').style.left = (e.clientX - 12.5) + 'px';
        document.querySelector('div').style.top = (e.clientY - 12.5) + 'px';
    }
});

document.querySelector('div').addEventListener('mouseup', function(e){
    hello = false;
    posY = Math.floor(parseInt(this.style.top));
    function Fall() {
        posY++;
        document.querySelector('div').style.top = posY + 'px';
        if (posY < parseInt(window.innerHeight) - 25) requestAnimationFrame(Fall);
    }
    Fall();
});

并且请始终以分号结束语句...