웹 앱에서 키보드 단축키 구현(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.)