События клавиатуры в JavaScript
События клавиатуры возникают, когда пользователь нажимает или отпускает клавишу. Они нужны для горячих клавиш, управления интерфейсом с клавиатуры и небольших действий вроде закрытия панели по Escape.
Обычные кнопки и ссылки уже можно активировать с клавиатуры. Не нужно заново реализовывать это поведение в обработчике keydown. События клавиатуры полезны там, где действительно нужна отдельная команда или управление компонентом.
keydown и keyup
keydown срабатывает в момент нажатия клавиши, а keyup - когда пользователь её отпускает. Для большинства задач этого достаточно. Событие keypress устарело, поэтому в новом коде его не используют.
<button class="key-demo" type="button">
Нажмите клавишу, пока кнопка в фокусе
</button>
<p class="key-result" aria-live="polite">
Здесь появится информация о клавише
</p>
const keyDemo = document.querySelector('.key-demo');
const keyResult = document.querySelector('.key-result');
keyDemo.addEventListener('keydown', function (event) {
keyResult.textContent = 'Нажатие: ' + event.key;
});
keyDemo.addEventListener('keyup', function (event) {
keyResult.textContent = 'Отпускание: ' + event.key;
});
Сначала нажмите на кнопку или перейдите к ней клавишей Tab. После этого обработчики покажут значение нажатой и отпущенной клавиши. Клавиатурные события получает элемент, который находится в фокусе.
event.key и event.code
Свойство event.key содержит значение клавиши с точки зрения пользователя. Для специальных клавиш это строки ‘Enter’, ‘Escape’ или ‘ArrowDown’. Для букв и символов значение зависит от раскладки и от нажатого Shift.
Свойство event.code описывает физическое положение клавиши. Например, у клавиши на месте латинской A значение code будет ‘KeyA’ даже при русской раскладке, когда key вернёт ‘ф’.
| Свойство | Когда использовать |
|---|---|
event.key | Нужна команда с понятным значением: Escape, Enter, стрелки или введённый символ |
event.code | Важно физическое место клавиши, например для управления в игре |
В большинстве интерфейсов подходит event.key. Не сравнивайте устаревшие числовые свойства keyCode и which - вместо них используйте key или code.
Замените обработчик keydown из первого примера на такой, чтобы увидеть оба свойства:
keyDemo.addEventListener('keydown', function (event) {
keyResult.textContent =
'key: ' + event.key + ', code: ' + event.code;
});
Попробуйте переключить раскладку и нажать одну и ту же физическую клавишу. key изменится, а code останется прежним.
Удержание клавиши
При удержании многих клавиш браузер начинает повторно отправлять keydown. У первого события свойство event.repeat равно false, у повторных - true. Событие keyup произойдёт один раз, когда клавишу отпустят.
Повтор бывает полезен, например при движении персонажа или прокрутке списка. Но команду, которую нужно выполнить только один раз, лучше защитить от повтора: if (event.repeat) return;. Проверка event.repeat особенно важна для открытия панели, отправки формы и других действий, которые не должны дублироваться.
Сочетания клавиш
У объекта события есть логические свойства ctrlKey, metaKey, shiftKey и altKey. Они показывают, была ли зажата клавиша-модификатор в момент события. Для сочетания, которое должно работать в Windows, Linux и macOS, обычно проверяют и ctrlKey, и metaKey. На macOS metaKey соответствует клавише Command.
<textarea
class="message-field"
rows="4"
placeholder="Напишите сообщение"
></textarea>
<p class="message-status" aria-live="polite"></p>
const messageField = document.querySelector('.message-field');
const messageStatus = document.querySelector('.message-status');
messageField.addEventListener('keydown', function (event) {
const isSendShortcut =
(event.ctrlKey || event.metaKey) &&
event.key === 'Enter';
if (!isSendShortcut || event.repeat) {
return;
}
event.preventDefault();
messageStatus.textContent = 'Сообщение отправлено';
});
Обычный Enter продолжит добавлять новую строку в поле. Сработает только сочетание Ctrl + Enter или Cmd + Enter. В реальном приложении вместо изменения текста вы вызовете функцию отправки сообщения.
Иногда сочетание заменяет действие браузера. В таком случае можно вызвать event.preventDefault(), но только после точной проверки сочетания. Не отменяйте поведение каждого keydown: это может сломать ввод текста, переход по Tab и другие привычные действия.
Фокус и ввод текста
Обработчик на конкретном элементе работает, пока элемент находится в фокусе. Это удобно для поля ввода, списка или другого компонента. Обработчик на document подходит только для действительно глобальной команды, например для закрытия уже открытой панели по Escape.
Глобальные сочетания не должны мешать пользователю печатать. Если команда не относится к текстовому полю, не выполняйте её, когда фокус находится в input, textarea или редактируемом элементе с contenteditable.
Не отслеживайте значение текста черезkeydown. Клавиша не всегда означает изменение текста: пользователь может вставить текст, использовать автозаполнение или экранную клавиатуру. Когда нужно получить новое значение поля, слушайте событиеinput.
Итого
Для нажатия и отпускания клавиши используйте keydown и keyup. В большинстве интерфейсов проверяйте event.key, а event.code оставляйте для сценариев, где важно положение клавиши. Учитывайте event.repeat при удержании, проверяйте модификаторы для сочетаний и не перехватывайте клавиатуру там, где пользователь вводит текст.