removeEventListener不在'keydown'事件上执行

问题描述

我有一个仪表板站点用户可以通过在站点窗口上的任意位置按“ l”或“ g”热键在列表视图或网格视图之间切换。由于此事件侦听器是在整个窗口的“ keydown”事件上调用的,因此,如果用户在网站上的搜索文本框中键入内容时输入“ l”或“ g”,则会导致网站切换视图的问题。

为缓解此问题,我的方法是在“ keydown”元素的搜索文本框元素上添加一个eventListener,以删除window元素上“ keydown”的eventListener。然后,我实现了一个计时器,该计时器在用户停止键入后开始倒计时3秒钟(通过在搜索文本框中添加“ keyup”事件的eventListener)。

经过3秒而未在搜索文本框上触发“ keydown”事件的情况下,然后我再次将“ keydown” eventListener添加回window元素。

JS代码

let timer;
let timeInterval = 3000; // milliseconds so equates to 3 seconds

let searchTextBox = document.querySelector("#search-textBox");

if (typeof (searchTextBox) != 'undefined' && searchTextBox != null) { // check if the search text Box was successfully created and inserted into the DOM
    searchTextBox.addEventListener('keydown',function () { // when key is pressed on the search text Box,remove the window eventListener
        window.removeEventListener('keydown',addViewHotKeys);
    });

    searchTextBox.addEventListener('keyup',function () { // start the timer after a key is released
        console.log('key lifted');
        clearTimeout(timer); // clear the timeout if it was already set
        if (searchTextBox.value) { // if the textBox has any input inside,set the timer to execute the finishedTyping function after the timeInterval milliseconds has elapsed
            timer = setTimeout(finishedTyping,timeInterval);
        }
    });

    function finishedTyping() {
        addViewHotKeys();
        console.log('times up');
    }
}

// Detect hotkeys for easy navigation on index.html
function addViewHotKeys() {
    window.addEventListener('keydown',function (event) {
        if (event.key === 'l') {
            if (state.display !== 'list') {
                state.display = 'list';
                renderViewSelection();
                renderDashboardplane();
            }
        } else if (event.key === 'g') {
            if (state.display !== 'grid') {
                state.display = 'grid';
                renderViewSelection();
                renderDashboardplane();
            }
        }
    });
}

window.addEventListener('load',function () {
    addViewHotKeys();
});

我在搜索文本框上的'keydown'和'keyup'eventListener成功触发(并且计时器通过在3秒后执行finishTyping函数来按​​预期工作)。但是,对于搜索框上的'keydown'事件监听器,它并没有删除window元素上的eventListener,我仍然无法找到原因。

解决方法

解决此问题的更简洁的方法可能是使用搜索文本框focusblur事件,而不是按键输入计时器。

以下示例在您将焦点放在输入元素上时删除了keydown事件侦听器,并在输入元素失去焦点时再次添加了它。您可以应用相同的技术来包含任何其他输入元素。

let searchTextBox = document.querySelector("#search-textbox");

// Detect hotkeys for easy navigation on index.html
function addViewHotKeys(event) {
  if (event.key === 'l') {
    console.log('l');
    
    // useful code here
    
  } else if (event.key === 'g') {
    console.log('g');
    
    // useful code here
  }
}

window.addEventListener('load',function () {
    searchTextBox.addEventListener('focus',function() {
        window.removeEventListener('keydown',addViewHotKeys);
    });
    
    searchTextBox.addEventListener('blur',function() {
        window.addEventListener('keydown',addViewHotKeys);
    });
    
    window.addEventListener('keydown',addViewHotKeys);
});
<p>Press the l or g key to log that letter to the console,except when the input has focus:</p>
<input id="search-textbox" type="search" value="" placeholder="search-textbox" />