feat: Extensive refactoring and modification to support any number of interfaces

This commit is contained in:
Gabe
2025-09-24 23:24:00 +08:00
parent 779c9fc850
commit 2a46939aa5
65 changed files with 2054 additions and 1947 deletions

View File

@@ -1,112 +1,106 @@
import { isSameSet } from "./utils";
/**
* 键盘快捷键监听
* @param {*} fn
* @param {*} target
* @param {*} timeout
* @returns
* 键盘快捷键监听
* @param {(pressedKeys: Set<string>, event: KeyboardEvent) => void} onKeyDown - Keydown 回调
* @param {(pressedKeys: Set<string>, event: KeyboardEvent) => void} onKeyUp - Keyup 回调
* @param {EventTarget} target - 监听的目标元素
* @returns {() => void} - 用于注销监听的函数
*/
export const shortcutListener = (fn, target = document, timeout = 3000) => {
const allkeys = new Set();
const curkeys = new Set();
let timer = null;
export const shortcutListener = (
onKeyDown = () => {},
onKeyUp = () => {},
target = document
) => {
const pressedKeys = new Set();
const handleKeydown = (e) => {
timer && clearTimeout(timer);
timer = setTimeout(() => {
allkeys.clear();
curkeys.clear();
clearTimeout(timer);
timer = null;
}, timeout);
if (e.code) {
allkeys.add(e.code);
curkeys.add(e.code);
fn([...curkeys], [...allkeys]);
}
const handleKeyDown = (e) => {
if (pressedKeys.has(e.code)) return;
pressedKeys.add(e.code);
onKeyDown(new Set(pressedKeys), e);
};
const handleKeyup = (e) => {
curkeys.delete(e.code);
if (curkeys.size === 0) {
fn([...curkeys], [...allkeys]);
allkeys.clear();
}
const handleKeyUp = (e) => {
// onKeyUp 应该在 key 从集合中移除前触发,以便判断组合键
onKeyUp(new Set(pressedKeys), e);
pressedKeys.delete(e.code);
};
target.addEventListener("keydown", handleKeydown, true);
target.addEventListener("keyup", handleKeyup, true);
target.addEventListener("keydown", handleKeyDown);
target.addEventListener("keyup", handleKeyUp);
return () => {
if (timer) {
clearTimeout(timer);
timer = null;
}
target.removeEventListener("keydown", handleKeydown);
target.removeEventListener("keyup", handleKeyup);
target.removeEventListener("keydown", handleKeyDown);
target.removeEventListener("keyup", handleKeyUp);
pressedKeys.clear();
};
};
/**
* 注册键盘快捷键
* @param {*} targetKeys
* @param {*} fn
* @param {*} target
* @returns
* @param {string[]} targetKeys - 目标快捷键数组
* @param {() => void} fn - 匹配成功后执行的回调
* @param {EventTarget} target - 监听目标
* @returns {() => void} - 注销函数
*/
export const shortcutRegister = (targetKeys = [], fn, target = document) => {
return shortcutListener((curkeys) => {
if (
targetKeys.length > 0 &&
isSameSet(new Set(targetKeys), new Set(curkeys))
) {
if (targetKeys.length === 0) return () => {};
const targetKeySet = new Set(targetKeys);
const onKeyDown = (pressedKeys, event) => {
if (targetKeySet.size > 0 && isSameSet(targetKeySet, pressedKeys)) {
event.preventDefault();
event.stopPropagation();
fn();
}
}, target);
};
const onKeyUp = () => {};
return shortcutListener(onKeyDown, onKeyUp, target);
};
/**
* 高阶函数:为目标函数增加计次和超时重置功能
* @param {() => void} fn - 需要被包装的函数
* @param {number} step - 需要触发的次数
* @param {number} timeout - 超时毫秒数
* @returns {() => void} - 包装后的新函数
*/
const withStepCounter = (fn, step, timeout) => {
let count = 0;
let timer = null;
return () => {
timer && clearTimeout(timer);
timer = setTimeout(() => {
count = 0;
}, timeout);
count++;
if (count === step) {
count = 0;
clearTimeout(timer);
fn();
}
};
};
/**
* 注册连续快捷键
* @param {*} targetKeys
* @param {*} fn
* @param {*} step
* @param {*} timeout
* @param {*} target
* @returns
* @param {string[]} targetKeys - 目标快捷键数组
* @param {() => void} fn - 成功回调
* @param {number} step - 连续触发次数
* @param {number} timeout - 每次触发的间隔超时
* @param {EventTarget} target - 监听目标
* @returns {() => void} - 注销函数
*/
export const stepShortcutRegister = (
targetKeys = [],
fn,
step = 3,
step = 2,
timeout = 500,
target = document
) => {
let count = 0;
let pre = Date.now();
let timer;
return shortcutListener((curkeys, allkeys) => {
timer && clearTimeout(timer);
timer = setTimeout(() => {
clearTimeout(timer);
count = 0;
}, timeout);
if (targetKeys.length > 0 && curkeys.length === 0) {
const now = Date.now();
if (
(count === 0 || now - pre < timeout) &&
isSameSet(new Set(targetKeys), new Set(allkeys))
) {
count++;
if (count === step) {
count = 0;
fn();
}
} else {
count = 0;
}
pre = now;
}
}, target);
const steppedFn = withStepCounter(fn, step, timeout);
return shortcutRegister(targetKeys, steppedFn, target);
};