KeyDown在按住不放时不会连续触发

3
我有一个 Plunkr,其中包含一个 div,我在其上绑定了 keydown 事件。按下左右箭头后,div 应开始移动。在所有浏览器中都可以正常工作,但当按键被按住时,第一个 keydown 事件会立即被触发(div 会移动一次),然后等待一段时间后才继续移动。
这意味着 keydown 事件仅被触发一次,然后浏览器等待检测是否有后续的 keyUp 事件,然后在短时间内(没有 keyup 时)继续触发 keydown 事件。
要查看问题,请将焦点保持在窗口上,按住右箭头,div 应该移动5px,然后等待,再继续移动问题:有没有解决方法,我可以按住键不放,div 就可以立即开始移动,而无需等待检测后续的 keyup (只有一次)?

$(function() {
  $(window).keydown(function(e) {
    console.log(e.keyCode)
    if (e.keyCode == 39)
      move(5, 'left', $('.mover'))
    else if (e.keyCode == 37)
      move(-5, 'left', $('.mover'))
  })

})

function move(offset, direction, target) {
  console.log($(target))
  $(target).css(direction, (parseInt($(target).css(direction)) + offset) + 'px')
}
.mover {
  height: 50px;
  width: 50px;
  display: inline-block;
  background: black;
  position: absolute;
  left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class='mover'></div>

5个回答

6
我建议使用超时机制,就像这个例子一样:

http://codepen.io/kevrowe/pen/qEgGVO


$(function() {
  var direction,
      movingTimeout = -1;

  $(window).on('keydown', function(e) {    
    if (e.keyCode == 39) {
      direction = 'right';
    } else if (e.keyCode == 37) {
      direction = 'left';
    }  

    startMoving(direction);
  });

  function stopMoving() {
    clearTimeout(movingTimeout);
    movingTimeout = -1;
  }

  function startMoving(direction) {
    if (movingTimeout === -1) {      
      loop(direction);
    }
  }

  function loop(direction) {
    move(direction === 'left' ? -5 : 5, $('.mover'));
    movingTimeout = setTimeout(loop, 10, direction);
  }

  function move(offset, $target) {
    $target.css('left', (parseInt($target.css('left')) + offset) + 'px')
  }

  $(window).on('keyup', function(e) {    
    stopMoving();
  });
})

2
当你想追踪的键发生keydown事件时,将此信息存储在某个映射或标志中。
当keyup事件发生时,清除给定键的标志。
然后,在计时器上,您可以轮询键映射的状态,并移动正在按下的任何键方向的对象。
可能有更好的解决方案,但我不知道除了轮询外如何测试按键是否按下。
在keyup上,还需要检查是否需要中断移动对象。

1
一种解决方法是在循环中持续运行移动函数,直到键盘松开。
if (e.keyCode == 39){
  var stop = setInterval(function(){ 
    move(5, 'left', $('.mover'))
  }, 25);

  window.on("keyup", function(){
    //stop the loop
    clearInterval(stop);
    //and remove the keyup listener
    window.off("keyup", arguments.callee);
  })
} else if //etc...

0

对于那些可能感兴趣的人,这里有另一种处理双向移动的方法。例如: + 键 = "东北" 方向:

const FPS       = 60;
const STEP      = 5; 
const UP_KEY    = 90; // Z
const DOWN_KEY  = 83; // S
const LEFT_KEY  = 81; // Q
const RIGHT_KEY = 68; // D

const pressedKeys = [];
let movingTimeout = null;

function handleKeyDown(e) {
  pressedKeys[e.keyCode] = true;
  switch(e.keyCode) {
    case DOWN_KEY:
    case LEFT_KEY:
    case RIGHT_KEY:
    case UP_KEY:
      e.preventDefault();
      startMoving();
  }
}

function handleKeyUp(e) {
  pressedKeys[e.keyCode] = false;
  const shouldStop = !pressedKeys[UP_KEY]
    && !pressedKeys[DOWN_KEY]
    && !pressedKeys[LEFT_KEY]
    && !pressedKeys[RIGHT_KEY]
  ;
  if(shouldStop) {
    stopMoving();
  }
}

function startMoving() {
  if(!movingTimeout){
    loop();
  }
}

function stopMoving() {
  clearTimeout(movingTimeout);
  movingTimeout = null;
}

function loop() {
  const x = pressedKeys[RIGHT_KEY] ? STEP
          : pressedKeys[LEFT_KEY] ? -STEP : 0;
  const y = pressedKeys[DOWN_KEY] ? STEP
          : pressedKeys[UP_KEY] ? -STEP : 0;
  move(x, y);
  movingTimeout = setTimeout(loop, 1000 / FPS);
}

function move(x, y) {
  // Implement you own logic here for positioning / handling collisions
  // Ex: store.dispatch({ type: "MOVE_PLAYER", x, y });
  console.log(`Moving ${x} ${y} !`);
}


window.addEventListener('keydown', e => handleKeyDown(e));
window.addEventListener('keyup', e => handleKeyUp(e));

希望这能有所帮助。
祝好!

0

纯 JavaScript

<input id="some" type="text">

var input=document.getElementById("some");
input.addEventListener("keydown",function(e){

if (e.which == 40) {
var stop = setInterval(function(){ 

 console.log("ss:");

        }, 60);
        window.addEventListener("keyup", function(){
            //stop the loop
            clearInterval(stop);
            //and remove the keyup listener
            window.removeEventListener("keyup", arguments.callee);
          })


     }


})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接