【问题标题】:JavaScript EventListener multiple keydown stops after one key triggers keyupJavaScript EventListener 多次 keydown 停止后一键触发 keyup
【发布时间】:2020-08-10 20:01:01
【问题描述】:

早上好,我遇到了EventListener 的问题。我有一个 keydown 事件,我检查是否按下了多个键或单次按下。

我的问题: 我有三种情况:(W + A) - (W + D) 或 W。按下 W + A 并释放 A 键后,触发了 keyup 事件。因此,从逻辑上讲,keydown 事件已停止,但要重新启动 keydown 事件,我必须释放 W 并再次按下它。即使 A 键按下后 W 键仍然按下,keydown 事件也不会再次开始。

我的问题: 有没有办法通过将 keydown 事件设置为 true 来启动事件备份有没有办法让 keydown 事件识别仍然按下的键而无需再次按下它。

按键事件:

        document.addEventListener("keydown", event => {
            if (!keyStatus) { keyStatus = keyDown(event); }
            if (Object.keys(keysDown).length < 2) {
                keysDown = (keysDown || []);
            } else { Object.keys(keysDown).forEach(k => delete keysDown[k]); }
            keysDown[event.keyCode] = true;
            switch (true) {
                case keysDown[65] && keysDown[87]:
                    if (currentCode.includes(68) || (currentCode.length <= 1 && currentCode.includes(87))) { currentCode = [] }
                    if (currentCode.includes(65) && currentCode.includes(87)) {
                        break;
                    } else { currentCode.push(65, 87); }
                    multiStatus = true
                    break;
                case keysDown[68] && keysDown[87]:
                    if (currentCode.includes(65) || (currentCode.length <= 1 && currentCode.includes(87))) { currentCode = [] }
                    if (currentCode.includes(68) && currentCode.includes(87)) {
                        break;
                    } else { currentCode.push(68, 87) }
                    multiStatus = true
                    break;
                case keysDown[87] && !multiStatus:
                    if (currentCode.includes(65) || currentCode.includes(68)) { currentCode = [] }
                    if (currentCode.length <= 1 && currentCode.includes(87)) {
                        break;
                    } else { currentCode.push(87) }
                    break;
                default:
                    multiStatus = false
                    break;
            }
        });
        document.addEventListener("keyup", event => {
            if (keyStatus) { keyStatus = keyUp(event); currentCode = []; multiStatus = false }
        });

我希望有人能够帮助我。提前致谢

【问题讨论】:

  • 你想让W上的keydown在A释放后持续触发吗?
  • 不完全(但同样的想法)。一些背景故事是汽车的运动。因此,使用 W,您将加速,使用 A&D,您将转向。因此,当我举起 A 或 D 时,我希望 keydown 事件继续。
  • @Teemu 我希望有一些足够用
  • 是的,我想是的。我认为你需要完全不同的方法。将 keydowns 存储在对象的属性中,并在 keyup 发生时删除属性/将其设置为 false。然后使用一个单独的“主循环”(间隔或最好requestAnimationFrame),并在该循环中,使用存储事件的对象的现有/真实属性。
  • 你认为你可以把这个作为答案。我想我明白了,但现在我脑子里有点模糊。

标签: javascript addeventlistener keydown


【解决方案1】:

备份事件即使不是不可能的,也非常困难和耗时。相反,单独注册键事件,创建一个“主循环”来读取注册表(以及执行其他操作)。下面的 sn-p 不是适合您的代码的直接解决方案,而是在一个简单的示例中介绍了按键注册表和主循环,说明如何在屏幕上控制元素。

const ball = {
  a: 0,
  d: 0,
  w: 0,
  z: 0,
  speed: 2,
  posX: 0,
  posY: 0,
  el: document.querySelector('.ball')
}

function regKeyStrokes(e) {
  if (!'adwz'.includes(e.key)) {return;}
  ball[e.key] = (event.type === 'keyup') ? 0 : 1;
}

function animate() {
  const dX = ball.a * -ball.speed + ball.d * ball.speed;
  const dY = ball.w * -ball.speed + ball.z * ball.speed;
  const cS = (dX * dY === 0) ? 1 : 0.707;
  ball.posX += cS * dX;
  ball.posY += cS * dY;
  ball.el.style.transform = `translate(${ball.posX}px, ${ball.posY}px)`;
  requestAnimationFrame(animate);
}

document.addEventListener('keyup', regKeyStrokes);
document.addEventListener('keydown', regKeyStrokes);

requestAnimationFrame(animate);
.ball {
   position: fixed;
   width: 50px;
   height: 50px;
   background: red;
   border-radius: 100%;
}
&lt;div class="ball"&gt;&lt;/div&gt;

在sn-p中,密钥注册表是ball对象的一部分(这当然可以是一个单独的对象)。寄存器中的属性由使用的键命名。击键和释放的监听独立于主循环,并且键注册表与这两个事件的监听器保持同步。

【讨论】:

  • 谢谢!这按我想要的方式工作。答案被接受并投票赞成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 2021-03-22
  • 1970-01-01
相关资源
最近更新 更多