Keydown 事件监听器不监听

Keydown Event Listener does not listen

我正在制作一个虚拟键盘,通过按下物理键,它的副本必须在屏幕上突出显示。问题是,当我按下按钮时,绝对没有任何反应。程序监听鼠标事件,这部分没问题。代码提取:

_createKeys() {
        const fragment = document.createDocumentFragment();
        const layout = [
            '`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 'backspace',
            'tab', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']',
            'caps lock', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '\', 'enter',
            'shiftLeft', '\', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 'shiftRight', 'arrowUp',
            'Ctrl', 'Win', 'Alt', 'space', 'Alt', 'Ctrl', 'arrowLeft', 'arrowDown', 'arrowRight'
        ];

        const createIconHTML = (icon_name) => {
            return `<i class="material-icons">${icon_name}</i>`;
        };

        layout.forEach(key => {
            const keyElement = document.createElement('button');
            const lineBreak = ['backspace', ']', 'enter', 'arrowUp'].indexOf(key) !== -1;
            keyElement.setAttribute('type', 'button');
            keyElement.classList.add('key');
            switch(key) {
                case 'caps lock':
                    keyElement.classList.add('key-wide');
                    keyElement.textContent = 'CapsLock';
                    keyElement.addEventListener("click", () => {
                        this._toggleCapsLock();
                        keyElement.classList.toggle('key-caps', this.properties.capsLock);
                    });
                    keyElement.addEventListener('keydown', (e) => {
                        if(e.key === 'CapsLock') console.log('pressed');
                    });
             }
            fragment.appendChild(keyElement);
            if (lineBreak) {
                fragment.appendChild(document.createElement('br'));
            }
        });
        return fragment;
    },

你只调用 switch case 内的 addEventListener 也调用 document 而不是元素,这只发生在大写字母上,所以这需要退出。 另外,既然只有一个 switch case,为什么不使用 if 条件呢?会让代码更易读。

您必须将 keydown 事件侦听器添加到 document 而不是 keyElement 否则事件只会在元素具有焦点时触发,如果光标在页面其他地方的文本字段中。

而不是:

keyElement.addEventListener('keydown', (e) => {
    if(e.key === 'CapsLock') console.log('pressed');
});

使用:

document.addEventListener('keydown', (e) => {
    if(e.key === 'CapsLock') console.log('pressed');
});

但是,向 document 添加 ~100 多个事件侦听器并不是一个好主意。您应该在 document 上创建一个事件侦听器,用于侦听所有按键事件并激活相应的虚拟键。

layout.forEach(key => {
  ...
  keyElement.dataset.key = encodeURIComponent(key);
  ...
});

document.addEventListener('keydown', event => {
  let k = encodeURIComponent(event.key);
  let vkey = document.querySelector(`[data-key="${k}"]`);
  vkey?.classList.add('pressed');
});