From 2616b67a6fe8ab8573c64b70b8b15d958abc234c Mon Sep 17 00:00:00 2001 From: Inside Date: Fri, 23 Aug 2019 20:00:58 +0800 Subject: [PATCH] feat: custom splitkey (#105) --- README-zh.md | 27 +++++++++ src/main.js | 145 ++++++++++++++++++++++++++++------------------- test/run.test.js | 11 ++++ 3 files changed, 125 insertions(+), 58 deletions(-) diff --git a/README-zh.md b/README-zh.md index ae9e195..9eeabdc 100644 --- a/README-zh.md +++ b/README-zh.md @@ -167,6 +167,11 @@ hotkeys('*','wcj', function(e){ if(hotkeys.ctrl) console.log('大哥你摁下了 ctrl 键!'); if(hotkeys.alt) console.log('大哥你摁下了 alt 键!'); }); + +// 可以设置自定义的分割符 +hotkeys('ctrl-y, ctrl-a', {splitKey: '-'}, function(e){ + console.log('you press bind keys') +}) ``` #### option @@ -229,9 +234,11 @@ hotkeys.setScope('scope1'); ## 解除绑定 +`hotkeys.unbind()` 解除绑定的所有快捷键 `hotkeys.unbind("ctrl+o, ctrl+alt+enter")` 解除绑定两组快捷键 `hotkeys.unbind("ctrl+o","files")` 解除绑定名字叫files钟的一组快捷键 + ```js // 解除绑定 'a' 程序函数 hotkeys.unbind('a'); @@ -252,6 +259,26 @@ hotkeys.unbind('a', example); hotkeys('a', 'issues', example); hotkeys.unbind('a', 'issues', example); ``` +```js +可以通过传入对象解除绑定的快捷键 +hotkeys.unbind({ + key: 'ctrl-e,ctrl-u', + scope: 'issues', + spitKey: '-' +}) +传入数组可同时解除多个scope下绑定的快捷键 +hotkeys.unbind([ + { + key: 'a, ctrl+r', + scope: 'issues', + }, + { + key: '+, ctrl-y', + scope: 'test', + splitKey: '-' + } +]) +``` ## 键判断 diff --git a/src/main.js b/src/main.js index 5b0bf84..b601092 100644 --- a/src/main.js +++ b/src/main.js @@ -7,14 +7,23 @@ let _scope = 'all'; // 默认热键范围 const elementHasBindEvent = []; // 已绑定事件的节点记录 // 返回键码 -const code = x => _keyMap[x.toLowerCase()] || _modifier[x.toLowerCase()] || x.toUpperCase().charCodeAt(0); +const code = x => + _keyMap[x.toLowerCase()] || + _modifier[x.toLowerCase()] || + x.toUpperCase().charCodeAt(0); // 设置获取当前范围(默认为'所有') -function setScope(scope) { _scope = scope || 'all'; } +function setScope(scope) { + _scope = scope || 'all'; +} // 获取当前范围 -function getScope() { return _scope || 'all'; } +function getScope() { + return _scope || 'all'; +} // 获取摁下绑定键的键值 -function getPressedKeyCodes() { return _downKeys.slice(0); } +function getPressedKeyCodes() { + return _downKeys.slice(0); +} // 表单控件控件判断 返回 Boolean // hotkey is effective only when filter return true @@ -35,13 +44,12 @@ function filter(event) { // 判断摁下的键是否为某个键,返回true或者false function isPressed(keyCode) { - if (typeof (keyCode) === 'string') { + if (typeof keyCode === 'string') { keyCode = code(keyCode); // 转换成键码 } return _downKeys.indexOf(keyCode) !== -1; } - // 循环删除handlers中的所有 scope(范围) function deleteScope(scope, newScope) { let handlers; @@ -88,58 +96,63 @@ function clearModifier(event) { } } -// 解除绑定某个范围的快捷键 -function unbind(key, scope, method) { - const multipleKeys = getKeys(key); - let keys; - let mods = []; - let obj; - // 通过函数判断,是否解除绑定 - // https://github.com/jaywcjlove/hotkeys/issues/44 - if (typeof scope === 'function') { - method = scope; - scope = 'all'; - } - - for (let i = 0; i < multipleKeys.length; i++) { - // 将组合快捷键拆分为数组 - keys = multipleKeys[i].split('+'); - - // 记录每个组合键中的修饰键的键码 返回数组 - if (keys.length > 1) { - mods = getMods(_modifier, keys); - } else { - mods = []; +function unbind(keysInfo, ...args) { + // unbind(), unbind all keys + if (!keysInfo) { + Object.keys(_handlers).forEach(key => delete _handlers[key]); + } else if (Array.isArray(keysInfo)) { + // support like : unbind([{key: 'ctrl+a', scope: 's1'}, {key: 'ctrl-a', scope: 's2', splitKey: '-'}]) + keysInfo.forEach((info) => { + if (info.key) eachUnbind(info); + }); + } else if (typeof keysInfo === 'object') { + // support like unbind({key: 'ctrl+a, ctrl+b', scope:'abc'}) + if (keysInfo.key) eachUnbind(keysInfo); + } else if (typeof keysInfo === 'string') { + // support old method + // eslint-disable-line + let [scope, method] = args; + if (typeof scope === 'function') { + method = scope; + scope = ''; } + eachUnbind({ + key: keysInfo, + scope, + method, + splitKey: '+', + }); + } +} - // 获取除修饰键外的键值key - key = keys[keys.length - 1]; - key = key === '*' ? '*' : code(key); - +// 解除绑定某个范围的快捷键 +const eachUnbind = ({ + key, scope, method, splitKey = '+', +}) => { + const multipleKeys = getKeys(key); + multipleKeys.forEach((originKey) => { + const unbindKeys = originKey.split(splitKey); + const len = unbindKeys.length; + const lastKey = unbindKeys[len - 1]; + const keyCode = lastKey === '*' ? '*' : code(lastKey); + if (!_handlers[keyCode]) return; // 判断是否传入范围,没有就获取范围 if (!scope) scope = getScope(); - - // 如何key不在 _handlers 中返回不做处理 - if (!_handlers[key]) return; - - // 清空 handlers 中数据, - // 让触发快捷键键之后没有事件执行到达解除快捷键绑定的目的 - for (let r = 0; r < _handlers[key].length; r++) { - obj = _handlers[key][r]; + const mods = len > 1 ? getMods(_modifier, unbindKeys) : []; + _handlers[keyCode] = _handlers[keyCode].map((record) => { // 通过函数判断,是否解除绑定,函数相等直接返回 - const isMatchingMethod = method ? obj.method === method : true; - - // 判断是否在范围内并且键值相同 + const isMatchingMethod = method ? record.method === method : true; if ( isMatchingMethod && - obj.scope === scope && - compareArray(obj.mods, mods) + record.scope === scope && + compareArray(record.mods, mods) ) { - _handlers[key][r] = {}; + return {}; } - } - } -} + return record; + }); + }); +}; // 对监听对应快捷键的回调函数进行处理 function eventHandler(event, handler, scope) { @@ -155,13 +168,19 @@ function eventHandler(event, handler, scope) { if ( (!_mods[y] && handler.mods.indexOf(+y) > -1) || (_mods[y] && handler.mods.indexOf(+y) === -1) - ) modifiersMatch = false; + ) { + modifiersMatch = false; + } } } // 调用处理程序,如果是修饰键不做处理 if ( - (handler.mods.length === 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91]) || + (handler.mods.length === 0 && + !_mods[16] && + !_mods[18] && + !_mods[17] && + !_mods[91]) || modifiersMatch || handler.shortcut === '*' ) { @@ -175,7 +194,6 @@ function eventHandler(event, handler, scope) { } } - // 处理keydown事件 function dispatch(event) { const asterisk = _handlers['*']; @@ -218,7 +236,11 @@ function dispatch(event) { // 对任何快捷键都需要做的处理 if (asterisk) { for (let i = 0; i < asterisk.length; i++) { - if (asterisk[i].scope === scope && ((event.type === 'keydown' && asterisk[i].keydown) || (event.type === 'keyup' && asterisk[i].keyup))) { + if ( + asterisk[i].scope === scope && + ((event.type === 'keydown' && asterisk[i].keydown) || + (event.type === 'keyup' && asterisk[i].keyup)) + ) { eventHandler(event, asterisk[i], scope); } } @@ -227,9 +249,14 @@ function dispatch(event) { if (!(key in _handlers)) return; for (let i = 0; i < _handlers[key].length; i++) { - if ((event.type === 'keydown' && _handlers[key][i].keydown) || (event.type === 'keyup' && _handlers[key][i].keyup)) { + if ( + (event.type === 'keydown' && _handlers[key][i].keydown) || + (event.type === 'keyup' && _handlers[key][i].keyup) + ) { if (_handlers[key][i].key) { - const keyShortcut = _handlers[key][i].key.split('+'); + const record = _handlers[key][i]; + const { splitKey } = record; + const keyShortcut = record.key.split(splitKey); let _downKeysCurrent = []; // 记录当前按键键值 for (let a = 0; a < keyShortcut.length; a++) { _downKeysCurrent.push(code(keyShortcut[a])); @@ -237,7 +264,7 @@ function dispatch(event) { _downKeysCurrent = _downKeysCurrent.sort(); if (_downKeysCurrent.join('') === _downKeys.sort().join('')) { // 找到处理内容 - eventHandler(event, _handlers[key][i], scope); + eventHandler(event, record, scope); } } } @@ -257,6 +284,7 @@ function hotkeys(key, option, method) { let i = 0; let keyup = false; let keydown = true; + let splitKey = '+'; // 对为设定范围的判断 if (method === undefined && typeof option === 'function') { @@ -268,13 +296,14 @@ function hotkeys(key, option, method) { if (option.element) element = option.element; // eslint-disable-line if (option.keyup) keyup = option.keyup; // eslint-disable-line if (option.keydown !== undefined) keydown = option.keydown; // eslint-disable-line + if (typeof option.splitKey === 'string') splitKey = option.splitKey; // eslint-disable-line } if (typeof option === 'string') scope = option; // 对于每个快捷键进行处理 for (; i < keys.length; i++) { - key = keys[i].split('+'); // 按键列表 + key = keys[i].split(splitKey); // 按键列表 mods = []; // 如果是组合快捷键取得组合快捷键 @@ -294,6 +323,7 @@ function hotkeys(key, option, method) { shortcut: keys[i], method, key: keys[i], + splitKey, }); } // 在全局document上设置快捷键 @@ -312,7 +342,6 @@ function hotkeys(key, option, method) { } } - const _api = { setScope, getScope, diff --git a/test/run.test.js b/test/run.test.js index 878e133..6f55170 100644 --- a/test/run.test.js +++ b/test/run.test.js @@ -84,6 +84,17 @@ describe('\n Hotkeys.js Test Case.\n', () => { await hotkeys.unbind('command+ctrl+shift+a'); }); + test('Custom splitKey Test Case', async () => { + await hotkeys('ctrl-a', {splitKey: '-'}, (e) => { + expect(e.ctrlKey).toBeTruthy(); + expect(hotkeys.getPressedKeyCodes()[0]).toBe(65); + }); + await __triggerKeyboardEvent(document.body, 65, { + ctrlKey: true + }); + await hotkeys.unbind(); + }) + test('HotKeys unbind Test Case', async () => { hotkeys('enter', (e) => { expect(e.keyCode).toBe(13);