ahooks
Version:
react hooks library
293 lines (292 loc) • 9.73 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _useLatest = _interopRequireDefault(require("../useLatest"));
var _utils = require("../utils");
var _domTarget = require("../utils/domTarget");
var _useDeepCompareWithTarget = _interopRequireDefault(require("../utils/useDeepCompareWithTarget"));
var _isAppleDevice = _interopRequireDefault(require("../utils/isAppleDevice"));
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
// 键盘事件 keyCode 别名
var aliasKeyCodeMap = {
'0': 48,
'1': 49,
'2': 50,
'3': 51,
'4': 52,
'5': 53,
'6': 54,
'7': 55,
'8': 56,
'9': 57,
backspace: 8,
tab: 9,
enter: 13,
shift: 16,
// Legacy alias kept for compatibility; standard name is "control".
ctrl: 17,
control: 17,
alt: 18,
// Legacy alias kept for compatibility; standard name is "pause".
pausebreak: 19,
pause: 19,
capslock: 20,
// Legacy alias kept for compatibility; standard name is "escape".
esc: 27,
escape: 27,
// Legacy alias kept for compatibility; standard name is "spacebar" (non-standard but widely used).
space: 32,
spacebar: 32,
pageup: 33,
pagedown: 34,
end: 35,
home: 36,
// Legacy aliases kept for compatibility; standard names are "arrowleft/arrowup/arrowright/arrowdown".
leftarrow: 37,
arrowleft: 37,
uparrow: 38,
arrowup: 38,
rightarrow: 39,
arrowright: 39,
downarrow: 40,
arrowdown: 40,
insert: 45,
"delete": 46,
a: 65,
b: 66,
c: 67,
d: 68,
e: 69,
f: 70,
g: 71,
h: 72,
i: 73,
j: 74,
k: 75,
l: 76,
m: 77,
n: 78,
o: 79,
p: 80,
q: 81,
r: 82,
s: 83,
t: 84,
u: 85,
v: 86,
w: 87,
x: 88,
y: 89,
z: 90,
leftwindowkey: 91,
rightwindowkey: 92,
meta: _isAppleDevice["default"] ? [91, 93] : [91, 92],
// Legacy alias kept for compatibility; standard name is "contextmenu".
selectkey: 93,
contextmenu: 93,
numpad0: 96,
numpad1: 97,
numpad2: 98,
numpad3: 99,
numpad4: 100,
numpad5: 101,
numpad6: 102,
numpad7: 103,
numpad8: 104,
numpad9: 105,
multiply: 106,
add: 107,
subtract: 109,
decimalpoint: 110,
divide: 111,
f1: 112,
f2: 113,
f3: 114,
f4: 115,
f5: 116,
f6: 117,
f7: 118,
f8: 119,
f9: 120,
f10: 121,
f11: 122,
f12: 123,
numlock: 144,
scrolllock: 145,
semicolon: 186,
equalsign: 187,
comma: 188,
dash: 189,
period: 190,
forwardslash: 191,
graveaccent: 192,
openbracket: 219,
backslash: 220,
closebracket: 221,
singlequote: 222
};
// 修饰键
var modifierKey = {
ctrl: function ctrl(event) {
return event.ctrlKey || event.type === 'keyup' && event.keyCode === 17;
},
shift: function shift(event) {
return event.shiftKey || event.type === 'keyup' && event.keyCode === 16;
},
alt: function alt(event) {
return event.altKey || event.type === 'keyup' && event.keyCode === 18;
},
meta: function meta(event) {
return event.metaKey || event.type === 'keyup' && aliasKeyCodeMap.meta.includes(event.keyCode);
}
};
// 判断合法的按键类型
function isValidKeyType(value) {
return (0, _utils.isString)(value) || (0, _utils.isNumber)(value);
}
// 根据 event 计算激活键数量
function countKeyByEvent(event) {
var countOfModifier = Object.keys(modifierKey).reduce(function (total, key) {
if (modifierKey[key](event)) {
return total + 1;
}
return total;
}, 0);
// 16 17 18 91 92 是修饰键的 keyCode,如果 keyCode 是修饰键,那么激活数量就是修饰键的数量,如果不是,那么就需要 +1
return [16, 17, 18, 91, 92].includes(event.keyCode) ? countOfModifier : countOfModifier + 1;
}
/**
* 判断按键是否激活
* @param [event: KeyboardEvent]键盘事件
* @param [keyFilter: any] 当前键
* @returns string | number | boolean
*/
function genFilterKey(event, keyFilter, exactMatch) {
// 浏览器自动补全 input 的时候,会触发 keyDown、keyUp 事件,但此时 event.key 等为空
if (!event.key) {
return false;
}
// 数字类型直接匹配事件的 keyCode
if ((0, _utils.isNumber)(keyFilter)) {
return event.keyCode === keyFilter ? keyFilter : false;
}
// 字符串依次判断是否有组合键
var genArr = keyFilter.split('.');
var genLen = 0;
var _iterator = _createForOfIteratorHelper(genArr),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var key = _step.value;
// 组合键
var genModifier = modifierKey[key];
// keyCode 别名
var aliasKeyCode = aliasKeyCodeMap[key.toLowerCase()];
if (genModifier && genModifier(event) || aliasKeyCode && aliasKeyCode === event.keyCode) {
genLen++;
}
}
/**
* 需要判断触发的键位和监听的键位完全一致,判断方法就是触发的键位里有且等于监听的键位
* genLen === genArr.length 能判断出来触发的键位里有监听的键位
* countKeyByEvent(event) === genArr.length 判断出来触发的键位数量里有且等于监听的键位数量
* 主要用来防止按组合键其子集也会触发的情况,例如监听 ctrl+a 会触发监听 ctrl 和 a 两个键的事件。
*/
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
if (exactMatch) {
return genLen === genArr.length && countKeyByEvent(event) === genArr.length ? keyFilter : false;
}
return genLen === genArr.length ? keyFilter : false;
}
/**
* 键盘输入预处理方法
* @param [keyFilter: any] 当前键
* @returns () => Boolean
*/
function genKeyFormatter(keyFilter, exactMatch) {
if ((0, _utils.isFunction)(keyFilter)) {
return keyFilter;
}
if (isValidKeyType(keyFilter)) {
return function (event) {
return genFilterKey(event, keyFilter, exactMatch);
};
}
if (Array.isArray(keyFilter)) {
return function (event) {
return keyFilter.find(function (item) {
return genFilterKey(event, item, exactMatch);
});
};
}
return function () {
return Boolean(keyFilter);
};
}
var defaultEvents = ['keydown'];
function useKeyPress(keyFilter, eventHandler, option) {
var _ref = option || {},
_ref$events = _ref.events,
events = _ref$events === void 0 ? defaultEvents : _ref$events,
target = _ref.target,
_ref$exactMatch = _ref.exactMatch,
exactMatch = _ref$exactMatch === void 0 ? false : _ref$exactMatch,
_ref$useCapture = _ref.useCapture,
useCapture = _ref$useCapture === void 0 ? false : _ref$useCapture;
var eventHandlerRef = (0, _useLatest["default"])(eventHandler);
var keyFilterRef = (0, _useLatest["default"])(keyFilter);
(0, _useDeepCompareWithTarget["default"])(function () {
var _a;
var el = (0, _domTarget.getTargetElement)(target, window);
if (!el) {
return;
}
var callbackHandler = function callbackHandler(event) {
var _a;
var keyEvent = event;
var genGuard = genKeyFormatter(keyFilterRef.current, exactMatch);
var keyGuard = genGuard(keyEvent);
var firedKey = isValidKeyType(keyGuard) ? keyGuard : keyEvent.key;
if (keyGuard) {
return (_a = eventHandlerRef.current) === null || _a === void 0 ? void 0 : _a.call(eventHandlerRef, keyEvent, firedKey);
}
};
var _iterator2 = _createForOfIteratorHelper(events),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var eventName = _step2.value;
(_a = el === null || el === void 0 ? void 0 : el.addEventListener) === null || _a === void 0 ? void 0 : _a.call(el, eventName, callbackHandler, useCapture);
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return function () {
var _a;
var _iterator3 = _createForOfIteratorHelper(events),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var eventName = _step3.value;
(_a = el === null || el === void 0 ? void 0 : el.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(el, eventName, callbackHandler, useCapture);
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
};
}, [events], target);
}
var _default = exports["default"] = useKeyPress;