react 监听键盘事件 hook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { useCallback, useEffect, MutableRefObject } from "react";

type keyType = KeyboardEvent["keyCode"] | KeyboardEvent["key"];
type keyFilter = keyType | Array<keyType>;
type EventHandler = (event: KeyboardEvent) => void;
type keyEvent = "keydown" | "keyup";
type BasicElement = HTMLElement | Element | Document | Window;
type TargetElement = BasicElement | MutableRefObject<null | undefined>;
type EventOptions = {
events?: Array<keyEvent>;
target?: TargetElement;
};

const modifierKey: any = {
ctrl: (event: KeyboardEvent) => event.ctrlKey,
shift: (event: KeyboardEvent) => event.shiftKey,
alt: (event: KeyboardEvent) => event.altKey,
meta: (event: KeyboardEvent) => event.metaKey
};

const defaultEvents: Array<keyEvent> = ["keydown"];

/**
* 判断对象类型
* @param obj 参数对象
* @returns String
*/
function isType<T>(obj: T): string {
return Object.prototype.toString
.call(obj)
.replace(/^\[object (.+)\]$/, "$1")
.toLowerCase();
}

/**
* 获取当前元素
* @param target TargetElement
* @param defaultElement 默认绑定的元素
*/
function getTargetElement(
target?: TargetElement,
defaultElement?: BasicElement
) {
if (!target) {
return defaultElement;
}

if ("current" in target) {
return target.current;
}

return target;
}

/**
* 按键是否激活
* @param event 键盘事件
* @param keyFilter 当前键
*/
const keyActivated = (event: KeyboardEvent, keyFilter: any) => {
const type = isType(keyFilter);
const { keyCode } = event;

if (type === "number") {
return keyCode == keyFilter;
}

const keyCodeArr = keyFilter.split(".");
// 符合条件的长度
let genLen = 0;
// 组合键
for (const key of keyCodeArr) {
const genModifier = modifierKey[key];

if ((genModifier && genModifier) || keyCode == key) {
genLen++;
}
}

return genLen === keyCodeArr.length;
};

/**
* 键盘按下预处理方法
* @param event 键盘事件
* @param keyFilter 键码集
*/
const genKeyFormate = (event: KeyboardEvent, keyFilter: any) => {
const type = isType(keyFilter);

if (type === "string" || type === "number") {
return keyActivated(event, keyFilter);
}

// 多个键
if (type === "array") {
return keyFilter.some((item: keyFilter) => keyActivated(event, item));
}
};

/**
* 监听键盘按下/松开
* @param keyCode
* @param eventHandler
* @param options
*/
const useKeyPress = (
keyCode: keyFilter,
eventHandler?: EventHandler,
options: EventOptions = {}
) => {
const { target, events = defaultEvents } = options;

const callbackHandler = useCallback(
(event) => {
if (genKeyFormate(event, keyCode)) {
typeof eventHandler === "function" && eventHandler(event);
}
},
[keyCode]
);

useEffect(() => {
const el = getTargetElement(target, window)!;

for (const eventName of events) {
el.addEventListener(eventName, callbackHandler);
}

return () => {
for (const eventName of events) {
el.removeEventListener(eventName, callbackHandler);
}
};
}, [keyCode, events, callbackHandler]);
};

export default useKeyPress;

使用方法

1
2
3
useKeyPress(["13", "108"], () => {
console.log("按下了回车");
});

点击下方链接查看运行效果:

Edit react 监听键盘事件 hook

参数

参数 说明 类型
keyFilter 按键 code keyType
EventHandler 事件回调函数 (event: KeyboardEvent) => void
options 可配置项 EventOptions

options

参数 说明 类型
events 触发事件 Array<keydown
target DOM 节点或 Ref 对象 HTMLElement Element

git:https://github.com/isxiaoxin/front_end_wheel/tree/master/hooks/useKeyPress