# 个性化快捷键绑定
在 React 应用中,我们可以使用 react-hotkeys-hook 库来实现快捷键绑定,但是在这里,我先暂时使用一下最原始的写法,哈哈。
# 思路
- 创建一个快捷键到事件的映射表
- 添加监听事件
- 获取当前按下的键
- 判断当前的阶段,如果是修改阶段,则修改对应事件的快捷键,如果是执行阶段,则执行对应事件
# 代码
import React, { useState, useEffect, useCallback } from 'react';
interface Shortcut {
event: () => void;
keys: string[];
}
function redo() {
console.log('Redo action');
}
function undo() {
console.log('Undo action');
}
function save() {
console.log('Save action');
}
const ShortcutManager: React.FC = () => {
// 快捷键事件映射表
const [shortcuts, setShortcuts] = useState<Shortcut[]>([
{ event: redo, keys: ['Control', 'z'] },
{ event: undo, keys: ['Control', 'y'] },
{ event: save, keys: ['Control', 's'] }
]);
// 编辑状态
const [editingIndex, setEditingIndex] = useState<number | null>(null);
// 新的快捷键
const [newKeys, setNewKeys] = useState<string[]>([]);
// 稳定的handleKeyDown函数
const handleKeyDown = useCallback((e: KeyboardEvent) => {
const newKey: string[] = [];
if (e.ctrlKey || e.metaKey) e.preventDefault();
if (e.ctrlKey) newKey.push('Control');
if (e.altKey) newKey.push('Alt');
if (e.shiftKey) newKey.push('Shift');
if (e.metaKey) newKey.push('Meta');
if (e.key !== 'Control' && e.key !== 'shift') newKey.push(e.key.toLowerCase());
if (editingIndex !== null) {
// 如果在编辑状态,更新新的快捷键
const updatedShortcuts = shortcuts.map((sc, idx) => {
if (idx === editingIndex) {
return { ...sc, keys: newKey };
}
return sc;
});
setShortcuts(updatedShortcuts);
} else {
// 如果不在编辑状态,执行对应的快捷键事件
const shortcut = shortcuts.find(sc => sc.keys.join('+') === newKey.join('+'));
shortcut?.event();
}
}, [editingIndex, shortcuts]);
// 添加和移除事件监听器
useEffect(() => {
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [editingIndex, handleKeyDown]);
const startEditing = (index: number) => {
setEditingIndex(index);
setNewKeys([]);
};
const stopEditing = () => {
setEditingIndex(null);
if (newKeys.length > 0) {
const updatedShortcuts = shortcuts.map((sc, idx) => idx === editingIndex ? { ...sc, keys: newKeys } : sc);
setShortcuts(updatedShortcuts);
}
};
return (
<div>
{shortcuts.map((sc, index) => (
<div key={index}>
<span>{sc.event.name}快捷键</span>
<span>{sc.keys.join('+')}</span>
{editingIndex === index ? (
<button onClick={stopEditing}>完成</button>
) : (
<button onClick={() => startEditing(index)}>修改</button>
)}
</div>
))}
</div>
);
};
function App() {
return (
<div className="App">
<ShortcutManager />
</div>
);
}
export default App;