【问题标题】:Prevent JavaScript keydown event from being handled multiple times while held down防止在按住时多次处理 JavaScript keydown 事件
【发布时间】:2011-05-22 12:34:56
【问题描述】:

我有这个代码:

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

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

【问题讨论】:

  • 你可以实现事件去抖动...
  • 感兴趣的,请参阅this page,其中(以及其他详细信息)指出keydown 事件不会在非 Windows Gecko 浏览器上自动重复。

标签: javascript


【解决方案1】:

编辑:现在每个浏览器都完全支持它。 除了 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网站上说可以在火狐上运行,我已经在Chrome中成功使用过,所以两大浏览器应该都没有问题

【讨论】:

  • 终于找到了一个干净的解决方案!
  • 很高兴您喜欢它,它也来自匈牙利,因此您会感觉它是本地采购的。 :D
【解决方案2】:
    var fired = false;

    element.onkeydown = function() {

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

然后使用 onkeyup 事件

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

【讨论】:

  • 我应该把这些东西放在哪里?只是一个新功能还是什么? (抱歉,我对 JavaScript 有点陌生)
  • @Chris 使用addEventListener(对于非旧IE)是注册处理程序的正确方法。关键是var fired=false; 应该在任一函数之外,以便两者可以共享(通过闭包的魔力)。
【解决方案3】:

试试这个:)

您可以通过简单地确定keydown 是否为真来确定脚本中的其他任何地方是否有按键按下!您还可以在按键按下时执行附加脚本,方法是将console.log(); 替换为按键按下时想要按下的任何内容。

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

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

【讨论】:

    【解决方案4】:

    上面的解决方案没有考虑多次按键(想象一个游戏,用户可以同时向上和离开,但只需要触发一次)。 我需要一个通用解决方案来禁用所有键的多个 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;
    }; 
    

    检查下面的sn-p:

    // 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>

    【讨论】:

      【解决方案5】:

      使用keyup 事件。当他们举起钥匙时会触发它。

      【讨论】:

      • 请注意,如果您尝试捕获浏览器使用的密钥,keyup 不会让您阻止默认操作(在大多数情况下)。 Use this site 获取有关触发顺序以及浏览器何时触发自己的事件的信息。
      【解决方案6】:

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

      1. 记下每次keydown事件发生时的时间戳

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

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

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

      【讨论】:

        【解决方案7】:

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

        对于 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;
            });
        })();
        

        【讨论】:

          【解决方案8】:

          与上面来自匈牙利的解决方案不同,如果e.repeat 为真,则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>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-01-09
            • 2012-04-28
            • 2010-10-30
            • 2017-05-15
            • 2020-08-15
            相关资源
            最近更新 更多