繁体   English   中英

使用 JavaScript 每次按下键时,即使它被按住,我如何才能只获取一次 keydown 事件?

[英]How can I get keydown events only once each time the key is pressed, even if it's held down, with JavaScript?

我正在制作一个青蛙复制品,我希望青蛙在我按下一个键时只移动一次,基本上是为了防止它在按住一个键时移动多次。

这是我处理keydown事件的代码的相关部分:

document.onkeydown = function(e) {
  var key = e.which || e.keyCode;

  if (key == 37){ frog.x = frog.x - 50; }
  if (key == 38){ frog.y = frog.y - 50; }
  if (key == 39){ frog.x = frog.x + 50; }
  if (key == 40){ frog.y = frog.y + 50; }
};

更新:

我让它在按住键时不移动,但现在它不会让我在我向右移动一次后立即移动,但如果我单击另一个按钮会重置,然后再次执行相同的操作:

 const canvas = document.getElementById('canvas'); const c = canvas.getContext('2d'); canvas.height = window.innerHeight; canvas.width = window.innerWidth; let frog = { x: 0, y: 0, fw: 50, fh: 50, fmx: 0, fmy: 0, }; let counter = 0; function animate() { requestAnimationFrame(animate); // Clear previous scene: c.clearRect(0, 0, window.innerWidth, window.innerHeight); // Draw frog: c.fillStyle = '#000' c.fillRect(frog.x, frog.y, frog.fw, frog.fh); // Movement of the frog with keys: document.onkeydown = function(e) { e = e || window.event; var key = e.which || e.keyCode; if (key == 65 && counter === 0) { frog.x = frog.x - 50, counter = 1 } if (key == 87 && counter === 0) { frog.y = frog.y - 50, counter = 1 } if (key == 68 && counter === 0) { frog.x = frog.x + 50, counter = 1 } if (key == 83 && counter === 0) { frog.y = frog.y + 50, counter = 1 } }; document.onkeyup = function(e) { e = e || window.event; var key = e.which || e.keyCode; if (key == 65) { counter = 0 } if (key == 87) { counter = 0 } if (key == 68) { coutner = 0 } if (key == 83) { counter = 0 } }; } animate();
 body { margin: 0; } #canvas { width: 100%; height: 100%; }
 <canvas id="canvas" />

您可以使用KeyboardEvent.repeat属性 ( e.repeat ) 来检查用户是否只是按住键而在这种情况下什么也不做。

基本上,您的代码应如下所示:

if (e.repeat) return; // Do nothing

const key = e.which || e.keyCode;

if (key === 37) frog.x = frog.x - 50;
else if (key === 38) frog.y = frog.y - 50;
else if (key === 39) frog.x = frog.x + 50;
else if (key === 40) frog.y = frog.y + 50;

此外, KeyboardEvent.whichKeyboardEvent.keyCode都已弃用,如文档中所述:

已弃用

不再推荐此功能。 尽管某些浏览器可能仍然支持它,但它可能已经从相关的 web 标准中删除,可能正在被删除,或者可能仅出于兼容性目的而保留。 避免使用它,并尽可能更新现有代码; 请参阅本页底部的兼容性表以指导您的决定。 请注意,此功能可能随时停止工作。

您应该改用KeyboardEvent.key

 const frog = { x: 500, y: 500 }; document.addEventListener('keydown', (e) => { e.preventDefault(); if (e.repeat) return; // Do nothing const { key } = e; switch(key) { case 'ArrowUp': frog.y = frog.y - 50; break; case 'ArrowRight': frog.x = frog.x + 50; break; case 'ArrowDown': frog.y = frog.y + 50; break; case 'ArrowLeft': frog.x = frog.x - 50; break; } if (key.startsWith('Arrow')) console.log(frog); });
 .as-console-wrapper { max-height: 100%;important; }

请注意,在您更新的代码中,您没有验证青蛙是否在 canvas 内,并且您正在渲染 function 内定义onkeydown侦听器。 您应该验证这一点并在外部仅定义一次偶数侦听器:

 const frog = { x: 0, y: 0, fw: 50, fh: 50, }; const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const MAX_X = window.innerWidth - frog.fw; const MAX_Y = window.innerHeight - frog.fh; canvas.width = window.innerWidth; canvas.height = window.innerHeight; function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#000'; ctx.fillRect(frog.x, frog.y, frog.fw, frog.fh); requestAnimationFrame(animate); } // This should be declared outside the rendering function: document.onkeydown = (e) => { e.preventDefault(); if (e.repeat) return; // Do nothing const { key } = e; switch(key) { case 'ArrowUp': frog.y = Math.max(0, frog.y - 50); break; case 'ArrowRight': frog.x = Math.min(frog.x + 50, MAX_X); break; case 'ArrowDown': frog.y = Math.min(frog.y + 50, MAX_Y); break; case 'ArrowLeft': frog.x = Math.max(0, frog.x - 50); break; } }; requestAnimationFrame(animate);
 body { margin: 0; } #canvas { width: 100%; height: 100%; }
 <canvas id="canvas" />

键盘驱动程序通常会触发重复的击键,这会变成不同的按键事件。 但是,使用此功能通常不是您想要的游戏,因为重复延迟很烦人,并且重复和初始重复延迟都是操作系统范围内的用户偏好。

相反,您应该捕获 keydown 和 keyup 事件。 当按键按下时,使用 setInterval 或 setTimeout 触发重复计时器和事件。 当键上升时,取消定时器。

我的首选是使用 setTimeout,以防您因为用户在按住键的同时用鼠标最小化他的 window 之类的事情而错过了 keyup 事件。

我做了那个人说的(顺便说一句很好的建议,我很高兴你告诉我),但是当我按下箭头时,形状消失了。


canvas.height = window.innerHeight;
canvas.width = window.innerWidth;

//variables

let frog = {
    x: 500,
    y: 500,
    fw: 50,
    fh: 50,
    fmx: 0,
    fmy: 0
}

//running it all

function animate(){
    requestAnimationFrame(animate)
    c.clearRect(0,0,innerWidth,innerHeight)

    //frog
    c.fillStyle = '#000'
    c.fillRect(frog.x,frog.y,frog.fw,frog.fh)


document.addEventListener('keydown', (e) => {
  e.preventDefault();

  if (e.repeat) return; // Do nothing

  const { key } = e;

  switch(key) {
    case 'ArrowUp':
      frog.y = frog.y - 50;
      break;

    case 'ArrowRight':
      frog.x = frog.x + 50;
      break;

    case 'ArrowDown':
      frog.y = frog.y + 50;
      break;

    case 'ArrowLeft':
      frog.x = frog.x - 50;
      break;  
  }
  if (key.startsWith('Arrow')) console.log(frog);
});

}

animate();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM