繁体   English   中英

防止 JavaScript keydown 事件在按住时被多次处理

[英]Prevent JavaScript keydown event from being handled multiple times while held down

我有这个代码:

else if (e.keyCode == 32){
      fired = true;

在 keyDown 函数中(我添加了 document.addEventListener 代码)。 现在它工作得很好,并且完全符合我的要求。 但问题是:如果你按住这个键,它会一遍又一遍地不断地使 fire = true 直到它被释放。 我只是想让它设置 fire = true; 一次,即使按键被按下。

编辑:现在除了 Internet Explorer 之外的所有浏览器都完全支持它

如果浏览器兼容性不是您的主要关注点* ,您可以尝试访问KeyboardEvent.repeat属性,如下所述:
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat

通过在你的处理函数中做这样的事情:

function keyDown (e) {
  if (e.repeat) { return }

  // do stuff here
}

您可以避免重复击键。


*:在MDN站点上说它可以在Firefox中运行,我在Chrome中成功使用了它,所以两大浏览器应该没有问题

    var fired = false;

    element.onkeydown = function() {

        if(!fired) {
            fired = true;
            // do something
        }
    };

然后使用 onkeyup 事件

    element.onkeyup = function() {
     fired = false;
    };

尝试这个 :)

您可以通过简单地确定keydown是否为真来确定脚本中的任何其他地方是否按下了键! 您还可以通过替换console.log();在某个键关闭时执行其他脚本console.log(); 当一个键被关闭时,无论你想关闭什么。

请告诉我这是否可以改进。

 var keydown = false; window.addEventListener('keydown', function() { if (!keydown) { keydown = true; console.log('key down'); } window.addEventListener('keyup', function() { keydown = false; }); });

处理此问题的另一种方法(由我的朋友建议):

  1. 请注意每次 keydown 事件发生时的时间戳

  2. 计算当前时间戳(t2)和前一个时间戳(t1)之间的差异

  3. (a) 如果差异小于某个预先确定的阈值,那么它是第二次 keydown(意味着我们已经执行了在该事件上发生的代码)。 因此,我们可能会选择不再执行代码

    (b) 如果差值大于预定阈值,则为第一个 keydown。 因此,我们将执行代码

上面的解决方案不考虑多次按键(想象一个游戏,用户可以同时按下向上和向左,但都只需要触发一次)。 我需要一个通用解决方案来禁用所有键的多个 keyPress 上的重复键:

// create an array with 222 (number of keycodes) values set to true
var keyEnabledArray = Array(222).fill(true);

document.onkeydown = function(e){
    // disable the key until key release
    if(keyEnabledArray[e.keyCode]) {
        keyEnabledArray[e.keyCode] = false;
    }
};

document.onkeyup = function(e){
    // enable the specific key on keyup
    keyEnabledArray[e.keyCode] = true;
}; 

检查下面的片段:

 // create an array with 222 true values var keyEnabledArray = Array(222).fill(true); document.onkeydown = function(e){ // disable the key until key release if(keyEnabledArray[e.keyCode]) { keyEnabledArray[e.keyCode] = false; document.getElementById('console').innerHTML += e.keyCode + '<br>'; } }; document.onkeyup = function(e){ keyEnabledArray[e.keyCode] = true; };
 Press a key: <div id='console'></div>

为避免重复keydown事件,请在触发后阻止它并使用keyup解除阻止。 你应该避免变量“fired”是全局的,所以在旧版本的 JS 中使用带有 ES6+ 的代码块或闭包。

对于 ES6:

{ let fired = false;    // code block to exclude 'fired' from global scope
    element.addEventListener('keydown', (e) => {
        // only accept key down when was released
        if(!fired) {
            fired = true;
            // check what key pressed...
            if (e.keyCode === 32) {
                // and do what you need with it
            }
        }
    });

    element.addEventListener('keyup', (e) => {
        fired = false;
    });
}

对于旧版本的 JS 使用 IIFE:

(function(){
    let fired = false;
    element.addEventListener('keydown', function(e) {
        // only accept key down when was released
        if(!fired) {
            fired = true;
            // check what key pressed...
            if (e.keyCode === 32) {
                // and do what you need with it
            }
        }
    });

    element.addEventListener('keyup', function(e) {
        fired = false;
    });
})();

使用keyup事件。 当他们的钥匙被解除时它被触发。

与上面来自匈牙利的解决方案不同,如果e.repeat为 true,则return false ,我的用例要求我执行以下操作以有效禁用文本输入/文本区域上的 onChange 事件。

function keyDown (e) {
  if(e.repeat) {
    e.preventDefault()
  }

  // do stuff here
}

我的用例的更大上下文(在 JSX 中):

<textarea 
  ref={formulaInput}
  defaultValue={formulaDefinition.string}
  onDoubleClick={handleLock} 
  onKeyUp={handleUnlock}
  onKeyDown={(e) => {
    if(e.repeat) {
      e.preventDefault()
    }
  }}
  onKeyPress={(e) => {
    if(e.repeat) {
      e.preventDefault()
    }
  }}
  readOnly={!focusLock}
  onChange={handleChange} 
  className={`formula-input ${focusLock ? 'formula-input__locked' : ''}`}
  id='2'
></textarea>

暂无
暂无

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

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