当我使用 onKeyDown 事件时移动元素被延迟

Moving elements is delayed when I'm using the onKeyDown event

我试图在按住某个键(在本例中为向左或向右箭头)时移动元素,但是当我按住某个键时,移动会延迟大约一秒钟。我使用了错误的事件还是我的代码有什么问题?

我正在使用 onKeyDown 事件来触发移动。

<head>
<script>
 var objX = 100;  
 function blockMove(e){
  if (e.keyCode == 37) { //move left
   objX-=4;
   document.getElementById("object").style.left = objX + "px"; 
  } else if (e.keyCode ==  39) { //move right
   objX+=4;
   document.getElementById("object").style.left = objX + "px"; 
  }
 }   
 </script>
</head>
<body onkeydown="blockMove(event)">
 <div id=object style="height:10px;width:80px;background-color:red;position:absolute;top:50px;left:100px"></div>
</body>

请耐心等待,这有点长而且可能有问题: (如果你想自己做的话也剧透一下)

<head>
<script>
    var objX = 100;     
   var leftDown = false;
   var rightDown = false;
        function blockMove(e){
            if(e.keyCode == 37 && !leftDown) { //move left
            leftDown = true;
                objX-=4;
                document.getElementById("object").style.left = objX + "px"; 
                }else if(e.keyCode ==  39 && !rightDown) { //move right
               rightDown = true;
                    objX+=4;
                    document.getElementById("object").style.left = objX + "px"; 
        }}
      function stopMove(e)
      {
         if( e.keyCode == 37 )
            leftDown = false;
         if( e.keyCode == 39 )
            rightDown = false;
      }
       function timer()
      {
         if( leftDown )
            objX -= 4;
         if( rightDown )
            objX += 4;
         document.getElementById("object").style.left = objX + "px";    
      }
      setInterval(timer, 100);
    </script>
</head>
<body onkeydown="blockMove(event)" onkeyup="stopMove(event)">
    <div id=object 
style="height:10px;width:80px;background-color:red;position:absolute;top:360px;left:100px"
    ></div>
</body>

而不是依赖于用户键盘重复率,这是最终导致多次调用 blockMove 的原因,您应该使用计时器来检查对象是否应该以一致的速率移动(每个在我下面的例子中是 20ms)。这意味着无论用户的重复率设置如何,这对所有用户来说都是一致的体验。

然后您需要跟踪对象是否应该移动。通过使用 keydownkeyup 事件,我们可以跟踪当前是否按下了左右键,然后只需在现有的 blockMove 函数中检查这些值:

//object to keep current state of keys
var keys = {
  left: false,
  right: false
};

function keydown(e) {
  //remember "down" state
  if (e.keyCode == 37)
    keys.left = true;
  if (e.keyCode == 39)
    keys.right = true;
}
function keyup(e) {
  //forget "down" state
  if (e.keyCode == 37)
    keys.left = false;
  if (e.keyCode == 39)
    keys.right = false;
}

var objX = 100;  
function blockMove(){
    //now check the key state, rather than the event object
    if (keys.left) { //move left
        objX -= 4;
    }
    if (keys.right) { //move right
        objX += 4;
    }
    document.getElementById("object").style.left = objX + "px"; 
}

//Call the movement function every 20ms
window.setInterval(blockMove, 20);
<body onkeydown="keydown(event)" onkeyup="keyup(event)">
 <div id=object style="height:10px;width:80px;background-color:red;position:absolute;top:50px;left:100px"></div>
</body>


正如下面评论中所讨论的,setInterval 仅保证调用函数之前的最短时间,并且可能会受到限制。除了四处移动 DOM 对象,学习这样的基础知识很好,但在某些时候你可能想看看 drawing directly onto <canvas> elements and using requestAnimationFrame 来处理回调,因为它是为动画设计的,不像 setTimeout/setInterval.