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按键 codekeyType
EventHandler事件回调函数(event: KeyboardEvent) => void
options可配置项EventOptions

options

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

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