# 个性化快捷键绑定

在 React 应用中,我们可以使用 react-hotkeys-hook 库来实现快捷键绑定,但是在这里,我先暂时使用一下最原始的写法,哈哈。

# 思路

  1. 创建一个快捷键到事件的映射表
  2. 添加监听事件
  3. 获取当前按下的键
  4. 判断当前的阶段,如果是修改阶段,则修改对应事件的快捷键,如果是执行阶段,则执行对应事件

# 代码

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;
更新于 阅读次数