两篇吃透按键事件:你应该了解的js键盘事件和使用注意事项

4,977 阅读3分钟

这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战


注:键盘事件中,event 事件类型为 KeyboardEvent

keydown 、keypress 和 keyup 键盘按键事件(种类)

js中的键盘事件分为这三种:keydown 、keypress 和 keyup,都继承了 KeyboardEvent 接口。

  • keydown:按下键盘时触发。
  • keypress:按下有值的键时触发,即按下 Ctrl、Alt、Shift、Meta 这样无值的键,这个事件不会触发。对于有值的键,按下时先触发 keydown 事件,再触发 keypress 事件。
  • keyup:松开键盘时触发。

按下松开一个键的事件顺序是:

  1. keydown
  2. keypress
  3. keyup

长按不松的键盘事件顺序是:

  1. keydown
  2. keypress
  3. keydown
  4. keypress
  5. ...(重复)
  6. keyup

KeyboardEvent.repeat 用于判断一个按键是否被按着不放

KeyboardEvent.repeat 返回的是布尔值,代表该键是否被按着不放。

如果一个键被按下一直不松手,浏览器会持续触发 keydown 和 keypress 事件,直到松开为止。由此可以判断长按不松手的特殊处理、是否重复这个键等。

推荐使用 event.key (e.keyCode 和 e.which 已经被遗弃,不推荐)

虽然不推荐使用 keyCode 和 which,但是几乎所有浏览器都保持着兼容支持!可以放心使用。

event.key 表示按下的是哪个字符(区分大小写)

event.key 可以准确的表示当前按下的是哪个字符,不能表示准确的物理按键,比如 键盘上部的数字键 和 数字小键盘 上的数字键,event.key 可以获取对应的数字字符。

event.key 对于字母是 区分大小写的,因此在判断时要注意区分。比如 输出测试 console.log("key:"+event.key);

关于 e.keyCode 和 e.which

e.keyCode 和 e.which 都表示键盘按键对应的数字值,是用于判断按下哪个键的常用属性。

下图是 MDN 中关于 e.keyCode 和 e.which 已经被遗弃后的推荐建议,更多内容详见 MDN KeyboardEvent

deprecated

使用 e.keyCode 和 e.which 一个最大的问题是,无法区分大小写。因为无论大写还是小写字母,其 keyCode 值都是一样的。当然还有其他问题,具体参见下面的介绍。

为什么不推荐使用keyCode?

关于 不推荐使用 keyCode 和 which,感觉更多的原因还是实际使用中的不方便。因为 keyCode 对应的是具体的物理键数字值,无法区分具体表示的是什么字符。

下面是更详细的几个 keyCode 问题:

  • 不同的字符共用一个 keyCode 值

keyCode对应的是物理键,像 <,>. 键、键盘上面的数字键 1!2@3#4$等,都是多个字符在同一个按键上,对应的 keyCode 会有重复。

如下,通过 keydown 事件,查看 keyCode 和 key 的不同。

window.addEventListener("keydown", function (e) {
            console.log(`keyCode:${e.keyCode} —— key:${e.key}`);
         })

不同的字符有相同的 keyCode,具体按的字符是哪个,需要再结合 shift 键判断。

字母的大小写也是这个情况。

  • 相同的按键 keyCode 可能不同

这种情况发生在全键盘中的小数字键上。相同的按键,按住 shift 后,keyCode 则不相同。

而上面字母大小写、顶部数字键等,按住 shift 后,相同的键 keyCode 是不变的。

  • 相同的字符 keyCode 可能不同

按照上面的示例,小数字键中的 8,同时对应 shift 按键下的 向上箭头(ArrowUp)。其 keyCode 为 38。而标准的向上箭头,同样 keyCode 也为 38。

也就是,字符相同,keyCode 应该相同。但是,如果,测试数字小键盘上的 +- 按键,和键盘上部的 数字键 右边的 加减按键,keyCode 值又是不同的。

也就是,相同的字符,keyCode 也可能不同

本部分主要参考 张鑫旭 大佬的 告别JS keyCode

组合键的事件监听使用 keydown

ctrlshift等和其他按键组合时,组合键的事件监听通常要使用 keydown 事件,keypresskeyup 监听不到。

比如监听打印快捷键 ctrl + p,并阻止打开打印的界面:

使用 event.code 实现:

【字母按键判断推荐 event.code,其他字符按键推荐使用 event.key

window.addEventListener("keydown", function (e) {
    if(e.ctrlKey && e.code=="KeyP"){
        e.preventDefault();
    }
});

如果想要 使用 event.key 判断,可能需要判断大小写:if(e.ctrlKey && (e.key=="p" || e.key=="P"))

常见的控制按键的判断,如 EnterCtrl 等不需要判断大小写,也更方便使用。

比如 判断回车键(Enter)

window.addEventListener("keydown", function (e) {
    if(e.key=="Enter"){
        console.log("回车键!");
    }
});

event.key 兼容支持是从 ie9 开始的,而 event.code 在 IE 全系列中都不支持,估计这也是 MDN 推荐使用 key 替代 keyCode 或 which 的原因。

使用 event.keyCode 实现:

如果 不支持 event.key(比如ie9以下)或 event.code(ie全系列不支持),则可以回到使用 event.keyCodeevent.which,因为浏览器目前全都支持。

window.addEventListener("keydown", function (e) {
    var keyCode = e.keyCode ? e.keyCode : e.which; 
    if(e.ctrlKey && keyCode==80){
        e.preventDefault();
    } 
});

关于 event.keyCode 的正常使用

以上面的示例为例:

ctrl键 的 keycode 是 17。而如果在组合按键中,判断 event.ctrlKey,但是,一般支持 ctrlKey 的浏览器,也都支持 event.key ,甚至也支持 event.code,因此,既然使用了 ctrlKey,同样也可以使用 event.key

而不考虑对 IE 的支持,则甚至也可以使用 event.code

不过 event.keyCode/event.which 由于兼容,基本是所有浏览器都在支持,因此,正常情况下,还是使用 event.keyCode 即可。

KeyboardEvent.getModifierState(keyArg) 方法返回特殊修饰键的状态

getModifierState() 用于返回修饰键的状态,如果按下返回true。一般用于更复杂的修饰键的判断。

比如 "AltGraph"(Alt 和 Ctrl)、"ScrollLock"、"Fn"(Function,但只在安卓上支持,并且似乎功能也有限)。

由于 getModifierState() 在很多系统下的支持受限,因此可能需要借助代码,对按键的按下和松开进行记录并判断,可能是更好的处理方式。这些将来下一篇进行介绍。

getModifierState 的介绍参见MDN

判断精确的物理按键使用 event.code

event.code 返回事件对应的物理按键表示的 code,是一个字符串。它可以精确的标识出不用的物理按键,这是 key 属性无法实现的。

比如 对于左右 Alt 键,event.key 都返回 Alt,而小键盘的数字键 和 键盘上部的数字键,event.key 也会返回相同的值。

event.code 是进行区分的。

如下是一个输出 code 和 key 的测试示例:

window.addEventListener("keydown", function (e) {
    console.log(`code:${e.code} —— key:${e.key}`);
});

尤其是上面,AltLeftAltRight 的区分。

特殊的功能键 altKey、ctrlKey、metaKey、shiftKey (修饰键的组合功能键判断)

这几个特殊的按键,可以直接通过 event. 属性获取到,它们是只读的bool值,表示是否按下了某个按键。

  • KeyboardEvent.altKey: 是否按下 AltOption 键。
  • KeyboardEvent.ctrlKey:是否按下 Ctrl 键。
  • KeyboardEvent.metaKey:是否按下 ⌘ Command 键。
  • KeyboardEvent.shiftKey:是否按下 Shift 键。

这些特殊键也叫修饰键,用于修改其他键的默认行为。通过结合一个修饰键与另一个键来执行不同的操作。

常常用于组合按键的判断。

比如是否按下复制键(ctrl + c):

window.addEventListener("keydown", function (e) {
          if(e.ctrlKey && e.code=="KeyC"){
              console.log("执行了 ctrl+c 复制");
          }
});

关于 44 的 keyCode 和 PrntScrn 需要使用 keyup 事件监听

keyCode 为 44 代表的是屏幕上的截屏键,即 Prt Sc SysRq/PrntScrn 一般位于键盘的右上侧,F12 键的右边(不同键盘小有差异)。

它是一个系统的截屏快捷键,用于截取整个屏幕到“剪贴板”(clipboard),按下截屏后,直接粘贴到某个位置即可。

PrntScrn 按键的监听需要使用 keyup 事件,其他事件 keypresskeydown 都无法监听到。

这也意味着,PrntScrn 按键事件无法被阻止。

window.addEventListener("keyup", function (e) {
    var keyCode = e.keyCode ? e.keyCode : e.which;
    if (keyCode == 44) {
        console.log(`code:${e.code} —— key:${e.key}`);
        console.log("PrntScrn键抬起");
        // e.preventDefault(); 无法阻止截屏
    }
});

输出:

code:PrintScreen —— key:PrintScreen
PrntScrn键抬起

关于输入框光标按键时中文输入法下 key、keyCode问题

如果,光标位于输入框中,同时使用中文输入法,按键的 keyCode 始终 229,且 key 始终是 Process。

当然,除了打中文字时,其他按键都是可以正确识别:

参考推荐

  • 参考

MDN KeyboardEvent 及 MDN 其他相关资料

  • 查询 key code 的网站推荐

推荐一个查询按键对应的 key、code、which 值的网站:keycode.info/

  • 一个键盘事件属性和状态的站点

这是一个更详细的,显示当前按键属性及状态的小游戏demo,能够显示当前按键发生的事件、事件属性和修饰键。

在线地址 js-keyevents-demo.vercel.app/ 和 github地址 github.com/atapas/js-k…

当然,实际开发中,自己直接进行测试输出查看即可,方便简单。