1

背景

项目中需要对网页的 UI 操作设置快捷键,但是我们的开发机是 Mac,用户使用的是 Windows。所以开发起来遇到一些小小的坑。现在我们来梳理下这些知识点。

基础知识

网页上要设置快捷键最基础的做法一般是监听 keydown 事件,然后通过监听函数参数获取一些按键相关的属性来判断用户按了哪些按键:

  document.addEventListener( 'keydown', function( event ){
    let key = event.key;
    if ( key === 'Enter' ) {
      console.log( '你按下的是回车键~' );
    }
  } );

上面的代码只是做一个示例,按键相关的属性有很多个,这些属性定义在 KeyboardEvent 这个接口中。keydown 事件监听函数接受的第一个参数 event 就实现了这个接口(event不仅仅实现了 KeyboardEvent 还实现了其他接口噢)。KeyboardEvent 这个接口是在 W3C 的 DOM 规范里面定义的,现在最新发布的规范版本是 DOM4。不过呢,KeyboardEvent 在 DOM4 中并没有什么更新,文档直接把其定义指向了 DOM3 中的 KeyboardEvent 接口定义。所以接下来,让我们看下规范中是如何定义键盘事件的。

KeyboardEvent

先介绍下我们常用的一些属性(规范地址):

  • KeyboardEvent.key
  • KeyboardEvent.code
  • KeyboardEvent.ctrlKey
  • KeyboardEvent.shiftKey
  • KeyboardEvent.altKey
  • KeyboardEvent.metaKey

KeyboardEvent.ctrlKey | shiftKey | altKey | metaKey 比较简单,表示当你按下键盘的时候,Ctrl | Shift | Alt | meta 按键是否已经被按下。如果已经被按下这些值就是 true,通常我们要运用组合键的判断会用到(譬如:Alt + a)。大家看到 meta 会疑惑这个是哪个键?在 Mac 平台上指的是 command 键(),而在 Windows 平台指的是 windows 键()。但是不是所有 Windows 电脑键盘都有 这个键的。接下来我们介绍下最重要的两个属性 key 和 code。

KeyboardEvent.key

如果你按下的按钮所代表的是一个可打印的字符(printed representation),那么这个 key 的值就是这个字符(譬如:a、Enter、Shift、CapsLock、Backspace)。如果是一些特殊字符呢,这个值就可能是 Unidentified。你要问哪些键是特殊字符,这个。。。伦家标准里面说了应键盘而异。这里说的是单独按一个按键的场景,组合键又不同了,key 出什么值是有一套简单的算法的:

key holds the key value of the key pressed. If the value is has a printed representation, it MUST be a non-empty Unicode character string, conforming to the algorithm for determining the key value defined in this specification.

这里我只介绍最基本的用法,不详述算法。

KeyboardEvent.code

这个值比较诡异,它表示你按了键盘上的哪个按键。你按 a,code 的值是 KeyA,你按左边的 Shift,code 的值是 ShiftLeft。什么意思呢?就是他表示你按的按键在键盘的哪个位置。这里就有趣了,因为不同语言的键盘同一个键代表的字符可能不同,但是位置是相同的。打个比方:KeyQ 代表的是我们普通键盘q按键。但是呢 Dvorak 键盘q这个位置的按钮代表的不是 q,而是'。所以如果你按同一个按钮,key 的值可能不同,code 的值会相同。

有了上述的几个值一般的单个按键和组合键都能检测到了,不过按照 web 标准的尿性你可能会猜到,那兼容性问题呢?查下兼容表。。。key 和 code 兼容性堪忧啊,都是浏览器高级版本支持或者根本不支持。那么怎么办?

非标准属性

KeyboardEvent 接口标准经历了许多草稿版本,首先在 DOM2 下由于没有协商一致,它被丢弃; DOM3 重新加入。这导致了在早期的 DOM2 版本中非标准的实现。

  • KeyboardEvent.char:如果是 printed 的字符,则值是这个字符,如果是按键没有对应的 printed 字符,值为空。(如果该按键用作插入多个字符的宏, 则此属性的值是整个字符串, 而不仅仅是第一个字符。)
  • KeyboardEvent.charCode:是按键字符对应的 Unicode 编码的数字。(对于其 char 属性包含多个字符的按键是该属性中第一个字符的 Unicode 值。)
  • KeyboardEvent.keyCode:返回一个代表你所按按键的数字,这个数字是和系统实现相关。
  • KeyboardEvent.which:通常和 keyCode 是一致的。

DOM3 规范中说这些过期的属性会因平台,键盘语言,键盘布局等等众多因素而导致其取值不统一。

兼容性

如果你要在不同的浏览器甚至不同的平台使用一套快捷键,你尝试上述所有说到的属性,你会发现表现几乎都不一致。有的情况是相同按钮[组合]对应同一个属性取出的值不同。譬如 Alt + a,当你在 a 按下去的时候去获取 KeyboardEvent.key 的值,Windows 平台得到的是a,而 Mac 平台下得到的是å。有的情况是上述 KeyboardEvent 中很多属性都不支持,你连挑的机会都没有,譬如老版本的 IE 几乎只支持 KeyboardEvent.keyCode 这一个属性。

经过大量的测试,如果你需要一个大路化通用的解决方案,只能使用 KeyboardEvent.keyCode 来做统一的判断。当然如果这不能满足你的要求,那么你可以通过 userAgent 来判断不同平台,针对不同平台采取不同的快捷键策略。以上就是对这个知识点的简单梳理,如果想要更深入的如了解键盘事件的模型,请参考下方附上的规范。

参考资料

  1. KeyboardEvent from MDN: https://developer.mozilla.org...
  2. KeyboardEvent in DOM3 Events Specification: https://w3c.github.io/uievent...

Bernie维尼
388 声望21 粉丝