设计思路
- 数据结构:
- 使用一个对象来存储所有注册的快捷键及其对应的回调函数和组件标识。例如:
{ 'Ctrl+A': { callback: () => {}, componentId: 'componentA' }, 'Ctrl+C': { callback: () => {}, componentId: 'componentB' } }
。
- 为每个组件分配一个唯一的标识(可以是组件的名称或生成的唯一ID),用于在组件卸载时取消对应的快捷键监听。
- 主要函数逻辑:
- 注册函数:接受快捷键组合(如
Ctrl+A
)、回调函数和组件标识作为参数,将其存储到上述数据结构中,并添加全局键盘事件监听器。在监听器中,判断按下的键组合是否与已注册的快捷键匹配,若匹配则执行对应的回调函数。
- 取消注册函数:接受组件标识作为参数,遍历数据结构,删除所有与该组件标识相关的快捷键记录,并在必要时更新全局键盘事件监听器,确保不再触发已卸载组件的快捷键回调。
核心代码示例
import React, { useEffect, useRef } from'react';
// 存储快捷键的对象
const shortcutRegistry = {};
// 注册快捷键
function registerShortcut(shortcut, callback, componentId) {
if (shortcutRegistry[shortcut]) {
throw new Error(`Shortcut ${shortcut} is already registered.`);
}
shortcutRegistry[shortcut] = { callback, componentId };
document.addEventListener('keydown', handleKeyDown);
}
// 取消注册快捷键
function unregisterShortcut(componentId) {
Object.keys(shortcutRegistry).forEach(shortcut => {
if (shortcutRegistry[shortcut].componentId === componentId) {
delete shortcutRegistry[shortcut];
}
});
if (Object.keys(shortcutRegistry).length === 0) {
document.removeEventListener('keydown', handleKeyDown);
}
}
// 处理键盘按下事件
function handleKeyDown(event) {
const keyCombination = getKeyCombination(event);
if (shortcutRegistry[keyCombination]) {
shortcutRegistry[keyCombination].callback(event);
}
}
// 获取键组合
function getKeyCombination(event) {
const keys = [];
if (event.ctrlKey) keys.push('Ctrl');
if (event.shiftKey) keys.push('Shift');
if (event.altKey) keys.push('Alt');
keys.push(event.key);
return keys.join('+');
}
// 示例组件A
function ComponentA() {
const componentId = 'componentA';
useEffect(() => {
registerShortcut('Ctrl+A', () => {
// 全选逻辑
console.log('全选操作');
}, componentId);
return () => {
unregisterShortcut(componentId);
};
}, []);
return <div>Component A</div>;
}
// 示例组件B
function ComponentB() {
const componentId = 'componentB';
useEffect(() => {
registerShortcut('Ctrl+C', () => {
// 复制逻辑
console.log('复制操作');
}, componentId);
return () => {
unregisterShortcut(componentId);
};
}, []);
return <div>Component B</div>;
}
function App() {
return (
<div>
<ComponentA />
<ComponentB />
</div>
);
}
export default App;