2
2
* hotkeys-js v3.13.3
3
3
* A simple micro-library for defining and dispatching keyboard shortcuts. It has no dependencies.
4
4
*
5
- * Copyright (c) 2023 kenny wong <[email protected] >
5
+ * Copyright (c) 2024 kenny wong <[email protected] >
6
6
* https://github.com/jaywcjlove/hotkeys-js.git
7
7
*
8
8
* @website : https://jaywcjlove.github.io/hotkeys-js
@@ -19,9 +19,14 @@ function addEvent(object, event, method, useCapture) {
19
19
if ( object . addEventListener ) {
20
20
object . addEventListener ( event , method , useCapture ) ;
21
21
} else if ( object . attachEvent ) {
22
- object . attachEvent ( "on" . concat ( event ) , ( ) => {
23
- method ( window . event ) ;
24
- } ) ;
22
+ object . attachEvent ( "on" . concat ( event ) , method ) ;
23
+ }
24
+ }
25
+ function removeEvent ( object , event , method , useCapture ) {
26
+ if ( object . removeEventListener ) {
27
+ object . removeEventListener ( event , method , useCapture ) ;
28
+ } else if ( object . deachEvent ) {
29
+ object . deachEvent ( "on" . concat ( event ) , method ) ;
25
30
}
26
31
}
27
32
@@ -156,9 +161,9 @@ for (let k = 1; k < 20; k++) {
156
161
}
157
162
158
163
let _downKeys = [ ] ; // 记录摁下的绑定键
159
- let winListendFocus = false ; // window是否已经监听了focus事件
164
+ let winListendFocus = null ; // window是否已经监听了focus事件
160
165
let _scope = 'all' ; // 默认热键范围
161
- const elementHasBindEvent = [ ] ; // 已绑定事件的节点记录
166
+ const elementEventMap = new Map ( ) ; // 已绑定事件的节点记录
162
167
163
168
// 返回键码
164
169
const code = x => _keyMap [ x . toLowerCase ( ) ] || _modifier [ x . toLowerCase ( ) ] || x . toUpperCase ( ) . charCodeAt ( 0 ) ;
@@ -235,7 +240,17 @@ function deleteScope(scope, newScope) {
235
240
if ( Object . prototype . hasOwnProperty . call ( _handlers , key ) ) {
236
241
handlers = _handlers [ key ] ;
237
242
for ( i = 0 ; i < handlers . length ; ) {
238
- if ( handlers [ i ] . scope === scope ) handlers . splice ( i , 1 ) ; else i ++ ;
243
+ if ( handlers [ i ] . scope === scope ) {
244
+ const deleteItems = handlers . splice ( i , 1 ) ;
245
+ deleteItems . forEach ( _ref2 => {
246
+ let {
247
+ element
248
+ } = _ref2 ;
249
+ return removeKeyEvent ( element ) ;
250
+ } ) ;
251
+ } else {
252
+ i ++ ;
253
+ }
239
254
}
240
255
}
241
256
}
@@ -271,6 +286,7 @@ function unbind(keysInfo) {
271
286
// unbind(), unbind all keys
272
287
if ( typeof keysInfo === 'undefined' ) {
273
288
Object . keys ( _handlers ) . forEach ( key => delete _handlers [ key ] ) ;
289
+ removeKeyEvent ( null ) ;
274
290
} else if ( Array . isArray ( keysInfo ) ) {
275
291
// support like : unbind([{key: 'ctrl+a', scope: 's1'}, {key: 'ctrl-a', scope: 's2', splitKey: '-'}])
276
292
keysInfo . forEach ( info => {
@@ -300,13 +316,13 @@ function unbind(keysInfo) {
300
316
}
301
317
302
318
// 解除绑定某个范围的快捷键
303
- const eachUnbind = _ref2 => {
319
+ const eachUnbind = _ref3 => {
304
320
let {
305
321
key,
306
322
scope,
307
323
method,
308
324
splitKey = '+'
309
- } = _ref2 ;
325
+ } = _ref3 ;
310
326
const multipleKeys = getKeys ( key ) ;
311
327
multipleKeys . forEach ( originKey => {
312
328
const unbindKeys = originKey . split ( splitKey ) ;
@@ -317,11 +333,15 @@ const eachUnbind = _ref2 => {
317
333
// 判断是否传入范围,没有就获取范围
318
334
if ( ! scope ) scope = getScope ( ) ;
319
335
const mods = len > 1 ? getMods ( _modifier , unbindKeys ) : [ ] ;
336
+ const unbindElements = [ ] ;
320
337
_handlers [ keyCode ] = _handlers [ keyCode ] . filter ( record => {
321
338
// 通过函数判断,是否解除绑定,函数相等直接返回
322
339
const isMatchingMethod = method ? record . method === method : true ;
323
- return ! ( isMatchingMethod && record . scope === scope && compareArray ( record . mods , mods ) ) ;
340
+ const isUnbind = isMatchingMethod && record . scope === scope && compareArray ( record . mods , mods ) ;
341
+ if ( isUnbind ) unbindElements . push ( record . element ) ;
342
+ return ! isUnbind ;
324
343
} ) ;
344
+ unbindElements . forEach ( element => removeKeyEvent ( element ) ) ;
325
345
} ) ;
326
346
} ;
327
347
@@ -445,10 +465,12 @@ function dispatch(event, element) {
445
465
}
446
466
// key 不在 _handlers 中返回
447
467
if ( ! ( key in _handlers ) ) return ;
448
- for ( let i = 0 ; i < _handlers [ key ] . length ; i ++ ) {
449
- if ( event . type === 'keydown' && _handlers [ key ] [ i ] . keydown || event . type === 'keyup' && _handlers [ key ] [ i ] . keyup ) {
450
- if ( _handlers [ key ] [ i ] . key ) {
451
- const record = _handlers [ key ] [ i ] ;
468
+ const handlerKey = _handlers [ key ] ;
469
+ const keyLen = handlerKey . length ;
470
+ for ( let i = 0 ; i < keyLen ; i ++ ) {
471
+ if ( event . type === 'keydown' && handlerKey [ i ] . keydown || event . type === 'keyup' && handlerKey [ i ] . keyup ) {
472
+ if ( handlerKey [ i ] . key ) {
473
+ const record = handlerKey [ i ] ;
452
474
const {
453
475
splitKey
454
476
} = record ;
@@ -465,11 +487,6 @@ function dispatch(event, element) {
465
487
}
466
488
}
467
489
}
468
-
469
- // 判断 element 是否已经绑定事件
470
- function isElementBind ( element ) {
471
- return elementHasBindEvent . indexOf ( element ) > - 1 ;
472
- }
473
490
function hotkeys ( key , option , method ) {
474
491
_downKeys = [ ] ;
475
492
const keys = getKeys ( key ) ; // 需要处理的快捷键列表
@@ -528,21 +545,35 @@ function hotkeys(key, option, method) {
528
545
} ) ;
529
546
}
530
547
// 在全局document上设置快捷键
531
- if ( typeof element !== 'undefined' && ! isElementBind ( element ) && window ) {
532
- elementHasBindEvent . push ( element ) ;
533
- addEvent ( element , 'keydown' , e => {
534
- dispatch ( e , element ) ;
535
- } , capture ) ;
548
+ if ( typeof element !== 'undefined' && window ) {
549
+ if ( ! elementEventMap . has ( element ) ) {
550
+ const keydownListener = function ( ) {
551
+ let event = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : window . event ;
552
+ return dispatch ( event , element ) ;
553
+ } ;
554
+ const keyupListenr = function ( ) {
555
+ let event = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : window . event ;
556
+ dispatch ( event , element ) ;
557
+ clearModifier ( event ) ;
558
+ } ;
559
+ elementEventMap . set ( element , {
560
+ keydownListener,
561
+ keyupListenr,
562
+ capture
563
+ } ) ;
564
+ addEvent ( element , 'keydown' , keydownListener , capture ) ;
565
+ addEvent ( element , 'keyup' , keyupListenr , capture ) ;
566
+ }
536
567
if ( ! winListendFocus ) {
537
- winListendFocus = true ;
538
- addEvent ( window , 'focus' , ( ) => {
568
+ const listener = ( ) => {
539
569
_downKeys = [ ] ;
540
- } , capture ) ;
570
+ } ;
571
+ winListendFocus = {
572
+ listener,
573
+ capture
574
+ } ;
575
+ addEvent ( window , 'focus' , listener , capture ) ;
541
576
}
542
- addEvent ( element , 'keyup' , e => {
543
- dispatch ( e , element ) ;
544
- clearModifier ( e ) ;
545
- } , capture ) ;
546
577
}
547
578
}
548
579
function trigger ( shortcut ) {
@@ -556,6 +587,58 @@ function trigger(shortcut) {
556
587
} ) ;
557
588
} ) ;
558
589
}
590
+
591
+ // 销毁事件,unbind之后判断element上是否还有键盘快捷键,如果没有移除监听
592
+ function removeKeyEvent ( element ) {
593
+ const values = Object . values ( _handlers ) . flat ( ) ;
594
+ const findindex = values . findIndex ( _ref4 => {
595
+ let {
596
+ element : el
597
+ } = _ref4 ;
598
+ return el === element ;
599
+ } ) ;
600
+ if ( findindex < 0 ) {
601
+ const {
602
+ keydownListener,
603
+ keyupListenr,
604
+ capture
605
+ } = elementEventMap . get ( element ) || { } ;
606
+ if ( keydownListener && keyupListenr ) {
607
+ removeEvent ( element , 'keyup' , keyupListenr , capture ) ;
608
+ removeEvent ( element , 'keydown' , keydownListener , capture ) ;
609
+ elementEventMap . delete ( element ) ;
610
+ }
611
+ }
612
+ if ( values . length <= 0 || elementEventMap . size <= 0 ) {
613
+ // 移除所有的元素上的监听
614
+ const eventKeys = Object . keys ( elementEventMap ) ;
615
+ eventKeys . forEach ( el => {
616
+ const {
617
+ keydownListener,
618
+ keyupListenr,
619
+ capture
620
+ } = elementEventMap . get ( el ) || { } ;
621
+ if ( keydownListener && keyupListenr ) {
622
+ removeEvent ( el , 'keyup' , keyupListenr , capture ) ;
623
+ removeEvent ( el , 'keydown' , keydownListener , capture ) ;
624
+ elementEventMap . delete ( el ) ;
625
+ }
626
+ } ) ;
627
+ // 清空 elementEventMap
628
+ elementEventMap . clear ( ) ;
629
+ // 清空 _handlers
630
+ Object . keys ( _handlers ) . forEach ( key => delete _handlers [ key ] ) ;
631
+ // 移除window上的focus监听
632
+ if ( winListendFocus ) {
633
+ const {
634
+ listener,
635
+ capture
636
+ } = winListendFocus ;
637
+ removeEvent ( window , 'focus' , listener , capture ) ;
638
+ winListendFocus = null ;
639
+ }
640
+ }
641
+ }
559
642
const _api = {
560
643
getPressedKeyString,
561
644
setScope,
0 commit comments