KeyboardEvent.key

只读属性 KeyboardEvent.key 返回用户按下的物理按键的值。它还与 shiftKey 等调节性按键的状态和键盘的区域 / 和布局有关。它的值由以下因素决定:

  • 如果按下的键拥有可打印的内容,则返回一个非空的 Unicode 字符来代表这个键的可打印内容。
  • 如果按下的键是一个控制键或特殊字符,则返回一个事先定义好的值,见预定义键值列表
  • 如果 KeyboardEvent 显示按下的键是一个死键(dead key),则键值为 "Dead"
  • 有些特殊键盘的键(比如多媒体键盘上用来控制媒体播放的扩展按键)在 Windows 下会触发 WM_APPCOMMAND 事件,而不会产生按键代码。虽然没有按键代码,这些事件将映射到 DOM 键盘事件中,并将列入 Windows 的“虚拟按键码”列表中。
  • 如果按键无法识别,则返回 "Unidentified"

KeyboardEvent 次序

KeyboardEvent 事件以一个预设的次序触发,理解这一点对于理解特定 KeyboardEventkey 属性值大有帮助。对于一个给定的按键操作,KeyboardEvent 将假定 Event.preventDefault 未调用并按下面次序触发:

  1. 首先触发 keydown 事件。如果按键长按且生成一个字符,则事件将以一个与平台实现方式相关的时间间隔持续发出,同时将只读属性 KeyboardEvent.repeat 设定为 true
  2. 如果按键生成的字符即将插入某个 <input><textarea> 或其它某个 HTMLElement.contentEditable 设为 true 的元素,则依次触发 beforeinputinput事件。注意某些实现中若支持 keypress 事件则可能将其触发。当按键长按时重复触发。
  3. 当按键松开时触发 keyup 事件。操作结束。

在次序1、3中,KeyboardEvent.key 属性按照事先定义的规则设定为恰当的值。

KeyboardEvent 次序示例

考虑使用美国或英国键盘布局生成的点击 shiftKey 和一个未知的 key 2 时的事件次序。

请检测以下两个测试用例:

  1. 按下并长按 shift 键,然后按下 key 2 并松开。下一步,松开 shift 键。
  2. 按下并长按 shift 键,然后按下并长按 key 2。然后松开 shift 键,最后松开 key 2

HTML

<div class="flex flex-left">
    <textarea rows="5" id="test-target"></textarea>
    <button id="btn-clear-console">清空控制台</button>
</div>
<div class="flex flex-right">
    <div id="console-log"></div>
</div>
<script src="main.js"></script>

CSS

body {
    -webkit-display: flex;
    display: flex;
}
    
.flex {
    padding-left: 20px;
    padding-right: 20px;
}
    
.flex-left {
    flex: 1;
    flex-grow: 1;
    -webkit-flex: 1;
    -webkit-flex-grow: 1;
}
    
.flex-right {
    flex: 2;
    flex-grow: 2;
    -webkit-flex: 2;
    -webkit-flex-grow: 2;
}
    
#test-target {
    display: block;
    width: 100%;
    margin-bottom: 10px;
    resize: none;
}

#console-log {
    overflow: auto;
}

JavaScript

let textarea = document.getElementById('test-target'),
consoleLog = document.getElementById('console-log'),
btnClearConsole = document.getElementById('btn-clear-console');

function logMessage(message) {
  let p = document.createElement('p');
  p.appendChild(document.createTextNode(message));
  consoleLog.appendChild(p);
}

textarea.addEventListener('keydown', (e) => {
  if (!e.repeat)
    logMessage(`第一个 keydown 事件。key 属性的值为"${e.key}"`);
  else
    logMessage(`keydown 事件重复。key 属性的值为"${e.key}"`);
});

textarea.addEventListener('beforeinput', (e) => {
  logMessage(`beforeinput 事件。你准备输入"${e.data}"`);
});

textarea.addEventListener('input', (e) => {
  logMessage(`input 事件。你刚刚输入了"${e.data}"`);
});

textarea.addEventListener('keyup', (e) => {
  logMessage(`keyup 事件。key 属性的值为"${e.key}"`);
});

btnClearConsole.addEventListener('click', (e) => {
  let child = consoleLog.firstChild;
  while (child) {
   consoleLog.removeChild(child);
   child = consoleLog.firstChild;
  }
});

运行结果

用例 1

当按下 shift 键时,首先触发 keydown 事件,然后将 key 属性的值设为 "Shift" 字符串。如果继续长按 shift 键,由于不会生成字符按键值,keydown 事件不会继续重复触发。

当按下 key 2 时,另一个 keydown 事件将会为这个新的按键动作触发,若使用的是美式键盘,它的 key 属性将被设为 "@" 字符,若为英式键盘,则会设为 """ 字符。这是因为 key 属性 "shift" 处于激活状态。由于生成了一个字符的按键值,beforeinput 和 input 事件随后触发。

松开 key 2 时,keyup 事件将触发,key 属性将会为不同键盘布局设定合适的字符值,比如 "@""""

最后在松开 shift 键时,另一个 keyup 事件触发,key 值将保持 "Shift" 不变。

用例 2

当按下 shift 键时,首先触发 keydown 事件,然后将 key 属性的值设为 "Shift" 字符串。如果继续长按 shift 键,由于不会生成字符按键值,keydown 事件不会继续重复触发。

当按下 key 2 时,另一个 keydown 事件将会为这个新的按键动作触发,若使用的是美式键盘,它的 key 属性将被设为 "@" 字符,若为英式键盘,则会设为 """ 字符。这是因上档键处于激活状态。由于生成了一个字符的按键值,beforeinput 和 input 事件随后触发。如果继续长按 2 键,则 keydown 事件将持续重复触发,同时将 KeyboardEvent.repeat 属性设置为 truebeforeinput 和 input 事件也将持续重复触发。

当松开 shift 键时,keyup 事件随之触发,且 key 属性保留为 "Shift"。此时请注意为  key 2 长按触发的重复 keydown 事件的 key 值会变成 "2",因为上档键不再处于激活状态。beforeinput 与 input 事件的 InputEvent.data 属性同理。

最终 key 2 松开,keyup 事件触发,但两种键盘布局的 key 属性均为 "2"。就是因为没有激活上档键。

 

示例

这个示例使用 EventTarget.addEventListener() 监听 keydown 事件。当我们事件触发时,将检测按键的值是否为代码所关注,如果是,就进行某项操作。(可能是给飞船转向,或者是调整电子表格中选中单元格的位置。)

window.addEventListener("keydown", function (event) {
  if (event.defaultPrevented) {
    return; // 如果事件已经在进行中,则不做任何事。
  }

  switch (event.key) {
    case "ArrowDown":
      // 按“↑”方向键时要做的事。
      break;
    case "ArrowUp":
      // 按“↓”方向键时要做的事。
      break;
    case "ArrowLeft":
      // 按“←”方向键时要做的事。
      break;
    case "ArrowRight":
      // 按“→”方向键时要做的事。
      break;
    case "Enter":
      // 按“回车”键时要做的事。
      break;
    case "Escape":
      // 按“ESC”键时要做的事。
      break;
    default:
      return; // 什么都没按就退出吧。
  }

  // 取消默认动作,从而避免处理两次。
  event.preventDefault();
}, true);

标准

 

标准 状态 备注
Document Object Model (DOM) Level 3 Events Specification
KeyboardEvent.key
Obsolete 初次定义,包括按键的值。

 

兼容性

Update compatibility data on GitHub
DesktopMobile
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung Internet
keyChrome Full support 51Edge Full support 12Firefox Full support 23IE Full support 9
Notes
Full support 9
Notes
Notes IE's implementation does not completely match the current spec because it is based on an older version of the spec.
Opera Full support 38Safari Full support YesWebView Android Full support 51Chrome Android Full support 51Firefox Android Full support 23Opera Android Full support 41Safari iOS Full support YesSamsung Internet Android Full support Yes
Dead keyChrome Full support 51Edge ? Firefox No support NoIE No support NoOpera Full support 38Safari ? WebView Android Full support 51Chrome Android Full support 51Firefox Android No support NoOpera Android Full support 41Safari iOS ? Samsung Internet Android ?
Non-printable keysChrome Full support 51Edge ? Firefox Full support 23IE Full support 9
Notes
Full support 9
Notes
Notes IE's implementation does not completely match the current spec because it is based on an older version of the spec.
Opera Full support 38Safari ? WebView Android Full support 51Chrome Android Full support 51Firefox Android Full support 23Opera Android Full support 41Safari iOS ? Samsung Internet Android ?
Printable keysChrome Full support 51Edge ? Firefox Full support 29IE Full support 9
Notes
Full support 9
Notes
Notes IE's implementation does not completely match the current spec because it is based on an older version of the spec.
Opera Full support 38Safari ? WebView Android Full support 51Chrome Android Full support 51Firefox Android Full support 29Opera Android Full support 41Safari iOS ? Samsung Internet Android ?

Legend

Full support  
Full support
No support  
No support
Compatibility unknown  
Compatibility unknown
See implementation notes.
See implementation notes.