KeyboardEvent: key 属性

Baseline 已广泛支持

此特性已得到良好确立,可跨多种设备和浏览器版本使用。自 2017 年 3 月起,所有浏览器均支持此特性。

KeyboardEvent 接口的只读属性 key 返回用户按下的键的值,该值会考虑修饰键(如 Shift)的状态以及键盘的区域设置和布局。

字符串。

其值确定方式如下:

  • 如果按下的键具有可打印的表示形式,则返回的值是一个非空的 Unicode 字符字符串,其中包含该键的可打印表示形式。例如:如果按下的键是 Space 键,则返回值是单个空格(" ")。如果按下的键是 B 键,则返回值是字符串 "b"。但是,如果同时按下了 Shift 键(因此 shiftKeytrue),则返回值是字符串 "B"
  • 如果按下的键是控制键或特殊字符,则返回值是 预定义键值 之一。
  • 如果 KeyboardEvent 表示按下了一个死键,则键值为 "Dead"
  • 一些特殊键盘键(例如多媒体键盘上用于控制媒体的扩展键)在 Windows 上不会生成键码;相反,它们会触发 WM_APPCOMMAND 事件。这些事件会映射到 DOM 键盘事件,并列在 Windows 的“虚拟键码”中,尽管它们实际上并不是键码。
  • 如果无法识别该键,则返回值是 Unidentified

KeyboardEvent 序列

每个 KeyboardEvent 都是按预定的序列触发的。对于给定的按键操作,假设没有调用 Event.preventDefault,触发的 KeyboardEvent 序列如下:

  1. 首先会触发一个 keydown 事件。如果按键被继续按下并且该键产生一个字符键,则该事件将以平台实现依赖的间隔继续触发,并且 KeyboardEvent.repeat 只读属性将设置为 true
  2. 如果该键产生一个字符键,该字符键会插入到可能的 <input><textarea>HTMLElement.contentEditable 设置为 true 的元素中,则会按顺序触发 beforeinputinput 事件类型。请注意,其他一些实现可能会触发 keypress 事件(如果支持)。当按键被按下时,事件会重复触发。
  3. 当按键被释放时,会触发一个 keyup 事件。这完成了整个过程。

在序列 1 和 3 中,KeyboardEvent.key 属性会被定义并根据前面定义的规则适当地设置为某个值。

KeyboardEvent 序列示例

比较使用美国键盘布局和使用英国键盘布局与 Shift2 键交互时生成的事件序列。

尝试使用以下两个测试用例进行实验:

  1. 按下并按住 Shift 键,然后按下 2 键并释放它。接下来,释放 Shift 键。
  2. 按下并按住 Shift 键,然后按下并按住 2 键。释放 Shift 键。最后,释放 2 键。

HTML

html
<div class="fx">
  <div>
    <textarea rows="5" name="test-target" id="test-target"></textarea>
    <button type="button" name="btn-reset" id="btn-reset">Reset</button>
  </div>
  <div class="flex">
    <pre id="console-log"></pre>
  </div>
</div>

CSS

css
.fx {
  -webkit-display: flex;
  display: flex;
  margin-left: -20px;
  margin-right: -20px;
}

.fx > div {
  padding-left: 20px;
  padding-right: 20px;
}

.fx > div:first-child {
  width: 30%;
}

.flex {
  -webkit-flex: 1;
  flex: 1;
}

#test-target {
  display: block;
  width: 100%;
  margin-bottom: 10px;
}

JavaScript

js
const textarea = document.getElementById("test-target");
const consoleLog = document.getElementById("console-log");
const btnReset = document.getElementById("btn-reset");

function logMessage(message) {
  consoleLog.innerText += `${message}\n`;
}

textarea.addEventListener("keydown", (e) => {
  if (!e.repeat) {
    logMessage(`Key "${e.key}" pressed [event: keydown]`);
  } else {
    logMessage(`Key "${e.key}" repeating [event: keydown]`);
  }
});

textarea.addEventListener("beforeinput", (e) => {
  logMessage(`Key "${e.data}" about to be input [event: beforeinput]`);
});

textarea.addEventListener("input", (e) => {
  logMessage(`Key "${e.data}" input [event: input]`);
});

textarea.addEventListener("keyup", (e) => {
  logMessage(`Key "${e.key}" released [event: keyup]`);
});

btnReset.addEventListener("click", (e) => {
  let child = consoleLog.firstChild;
  while (child) {
    consoleLog.removeChild(child);
    child = consoleLog.firstChild;
  }
  textarea.value = "";
});

结果

注意: 在不支持 InputEvent 接口(用于 beforeinputinput 事件)的浏览器中,日志输出的这些行可能会出现不正确的输出。

情况 1

当按下 Shift 键时,首先会触发 keydown 事件,并且 key 属性值被设置为字符串 Shift。由于我们一直按住该键,因此 keydown 事件不会重复触发,因为它不产生字符键。

当按下 2 键 时,会为这次新的按键触发另一个 keydown 事件,并且由于活动的修饰键 shift,该事件的 key 属性值被设置为字符串 @(适用于美国键盘类型)和 "(适用于英国键盘类型)。接下来会触发 beforeinputinput 事件,因为该键产生了一个字符。

当释放 2 键 时,会触发一个 keyup 事件,并且 key 属性将分别保持 @" 的字符串值,具体取决于键盘布局。

当我们最终释放 shift 键时,会为它触发另一个 keyup 事件,并且 key 属性值将保持为 Shift

情况 2

当按下 Shift 键时,首先会触发 keydown 事件,并且 key 属性值被设置为字符串 Shift。由于我们一直按住该键,因此 keydown 事件不会重复触发,因为它不产生字符键。

当按下 2 键 时,会为这次新的按键触发另一个 keydown 事件,并且由于活动的修饰键 shift,该事件的 key 属性值被设置为字符串 @(适用于美国键盘类型)和 "(适用于英国键盘类型)。接下来会触发 beforeinputinput 事件,因为该键产生了一个字符。当按住该键时,keydown 事件会重复触发,并且 KeyboardEvent.repeat 属性被设置为 truebeforeinputinput 事件也会重复触发。

当我们释放 shift 键时,会为它触发一个 keyup 事件,并且 key 属性值保持为 Shift。此时,请注意,由于修饰键 shift 不再处于活动状态,因此对于重复按下的 2 键 的 keydown 事件,key 属性值现在是 "2"。这同样适用于 beforeinputinput 事件的 InputEvent.data 属性。

当我们最终释放 2 键 时,会触发一个 keyup 事件,但 key 属性将被设置为字符串值 2(适用于两种键盘布局),因为修饰键 shift 不再处于活动状态。

示例

此示例使用 EventTarget.addEventListener() 来监听 keydown 事件。当它们发生时,会检查按键的值,看它是否是我们代码感兴趣的按键之一,如果是,则以某种方式处理它(可能是通过控制航天器,或者改变电子表格中的选定单元格)。

js
window.addEventListener("keydown", (event) => {
  if (event.defaultPrevented) {
    return; // Do nothing if the event was already processed
  }

  switch (event.key) {
    case "ArrowDown":
      // Do something for "down arrow" key press.
      break;
    case "ArrowUp":
      // Do something for "up arrow" key press.
      break;
    case "ArrowLeft":
      // Do something for "left arrow" key press.
      break;
    case "ArrowRight":
      // Do something for "right arrow" key press.
      break;
    case "Enter":
      // Do something for "enter" or "return" key press.
      break;
    case " ":
      // Do something for "space" key press.
      break;
    case "Escape":
      // Do something for "esc" key press.
      break;
    default:
      return; // Quit when this doesn't handle the key event.
  }

  // Cancel the default action to avoid it being handled twice
  event.preventDefault();
});

规范

规范
UI 事件
# dom-keyboardevent-key

浏览器兼容性