웹 앱에서 키보드 단축키 구현(Vanilla JS 및 React 샘플 포함)
이 기사는 YAMAP 엔지니어 Advent Calendar 2019의 10일째 기사입니다.
연투로 죄송하지만, 아무쪼록 잘 부탁드립니다.
소개
현재 실시하고 있는 사내 어플리케이션의 개발에 있어서, 좋은 느낌의 인터페이스의 키보드 단축키를 구현하고 싶다고 생각해 시행착오했습니다. 그 결과, 비교적 이미지에 가까운 것을 할 수 있었으므로 공유합니다.
사용할 라이브러리
스크래치로 개발하는 것은 windows 의
ctrlKey
와 mac 의 metaKey
의 취급 등, 비교적 번거로울 것 같았으므로, 이하의 라이브러리를 사용하고 있습니다.HotKeys.js
키코드
event.keyCode
를 키맵 에 따라 문자열로 변환이번에 만드는 것
아래와 같은 인터페이스의 키보드 단축키를 구현합니다.
interface KeyMap {
sequence: string; // 'ctrl+a', 'ctrl+shift+a', ...
handler(evt: Event): void;
}
type KeyMaps = KeyMap[];
HotKeys.js도 상당히 다기능이지만 그대로 위의 인터페이스의 키보드 단축키를 구현하려면 조금 번거로운 일을 해야 한다고 했습니다. (HotKeys.js 단독으로의 구현은 후술. 의외로 번거롭지 않았다

Vanilla JavaScript (Babel)로 구현
hotkeys.js
import hotkeys from 'hotkeys-js';
import keycode from 'keycode';
import { undo, redo } from './funcs'; // undo, redo 関数は既に実装されているものを import
const orderedModifierKeys = Object.freeze(['command', 'ctrl', 'shift', 'alt']);
const getKeySequence = (codes, options = {
splitKey = '+',
}) => {
const keys = codes
.map(code => keycode(code)) // keycode() で keyCode に対応した文字列へ変換
.map(code => (code.endsWith('command') ? 'command' : code)); // command キーは 'left command', 'right command' として取得されるため、'command' に統一
const modifierKeys = keys
.filter(orderedModifierKeys.includes)
.sort((a, b) => { // modifierKeys を orderedModifierKeys の順番に並べ替える
const aIndex = orderedModifierKeys.findIndex(key => key === a);
const bIndex = orderedModifierKeys.findIndex(key => key === b);
return aIndex - bIndex;
});
const otherKeys = keys.filter(key => !orderedModifierKeys.includes(key));
return modifierKeys.concat(otherKeys).join(splitKey);
};
const keyMaps = [
{
sequence: 'command+z',
handler:() => undo(),
},
{
sequence: 'command+shift+z',
handler: () => redo(),
},
// ... other cases
];
const registerHotkeys = () => {
hotkeys('*', evt => {
const keyCodes = hotkeys.getPressedKeyCodes();
const sequence = getKeySequence(keyCodes);
const keyMap = keyMaps.find(keyMap => keyMap.sequence === sequence);
if (!keyMap) return; // ショートカットが存在しない場合は何もしない
keyMap.handler(evt);
})
}
const unregisterrHotkeys = () => {
hotkeys.unbind('*');
}
window.onload = () => {
registerHotkeys();
}
window.onbeforeunload = () => {
unregisterrHotkeys();
}
React에서 구현
React에서는 useHotkeys라는 Custom Hook을 구현해 보겠습니다.
useHotkeys.ts
import { useEffect } from 'react';
import hotkeys from 'hotkeys-js';
import keycode from 'keycode';
// --- 中略 ---
export const useHotkeys = (): void => {
const keyMaps = [
// ...
];
useEffect(() => {
hotkeys('*', (evt: Event) => {
const keyCodes = hotkeys.getPressedKeyCodes();
const sequence = getKeySequence(keyCodes);
const keyMap = keyMaps.find(keyMap => keyMap.sequence === sequence);
if (!keyMap) return;
keyMap.handler(evt);
});
return () => {
hotkeys.unbind('*');
};
}, [keyMaps]
};
이상
이상입니다.
사족이지만 어려운 일을 하지 않고 키보드 단축키를 구현한다면 HotKeys.js 에서 아래와 같은 구현을 하는 것이 빠를지도 모릅니다.
import hotkeys from 'hotkeys-js';
const keyMaps = [
{
sequence: 'ctrl+a',
handler: handleKeypressCtrlA,
},
];
const sequences = keyMaps.map(keyMap => keyMap.sequence)
hotkeys(sequences.join(','), (evt, handler) => {
const keyMap = keyMaps.find(({ sequence }) => sequence === handler.key);
if (!keyMap) return;
keyMap.handler(evt);
});
Reference
이 문제에 관하여(웹 앱에서 키보드 단축키 구현(Vanilla JS 및 React 샘플 포함)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/sotszk/items/1e060f0db0c61ec4f9d5텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)