@whitesev/domutils 1.9.2 → 1.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +58 -58
  2. package/dist/index.amd.js +53 -30
  3. package/dist/index.amd.js.map +1 -1
  4. package/dist/index.amd.min.js +1 -1
  5. package/dist/index.amd.min.js.map +1 -1
  6. package/dist/index.cjs.js +53 -30
  7. package/dist/index.cjs.js.map +1 -1
  8. package/dist/index.cjs.min.js +1 -1
  9. package/dist/index.cjs.min.js.map +1 -1
  10. package/dist/index.esm.js +53 -30
  11. package/dist/index.esm.js.map +1 -1
  12. package/dist/index.esm.min.js +1 -1
  13. package/dist/index.esm.min.js.map +1 -1
  14. package/dist/index.iife.js +53 -30
  15. package/dist/index.iife.js.map +1 -1
  16. package/dist/index.iife.min.js +1 -1
  17. package/dist/index.iife.min.js.map +1 -1
  18. package/dist/index.system.js +53 -30
  19. package/dist/index.system.js.map +1 -1
  20. package/dist/index.system.min.js +1 -1
  21. package/dist/index.system.min.js.map +1 -1
  22. package/dist/index.umd.js +53 -30
  23. package/dist/index.umd.js.map +1 -1
  24. package/dist/index.umd.min.js +1 -1
  25. package/dist/index.umd.min.js.map +1 -1
  26. package/dist/types/src/ElementEvent.d.ts +2 -2
  27. package/dist/types/src/types/DOMUtilsCSSProperty.d.ts +36 -36
  28. package/dist/types/src/types/DOMUtilsEvent.d.ts +437 -420
  29. package/dist/types/src/types/WindowApi.d.ts +14 -14
  30. package/dist/types/src/types/env.d.ts +10 -10
  31. package/dist/types/src/types/global.d.ts +1 -1
  32. package/dist/types/src/types/gm.d.ts +2 -2
  33. package/index.ts +3 -3
  34. package/package.json +21 -22
  35. package/src/CommonUtils.ts +163 -163
  36. package/src/ElementAnimate.ts +290 -290
  37. package/src/ElementEvent.ts +1593 -1569
  38. package/src/ElementHandler.ts +43 -43
  39. package/src/ElementSelector.ts +307 -289
  40. package/src/ElementWait.ts +742 -742
  41. package/src/GlobalData.ts +5 -5
  42. package/src/OriginPrototype.ts +5 -5
  43. package/src/Utils.ts +388 -388
  44. package/src/WindowApi.ts +59 -59
  45. package/src/index.ts +2052 -2052
  46. package/src/types/DOMUtilsCSSProperty.d.ts +36 -36
  47. package/src/types/DOMUtilsEvent.d.ts +437 -420
  48. package/src/types/WindowApi.d.ts +14 -14
  49. package/src/types/env.d.ts +10 -10
  50. package/src/types/global.d.ts +1 -1
  51. package/src/types/gm.d.ts +2 -2
@@ -1,1569 +1,1593 @@
1
- import { CommonUtils } from "./CommonUtils";
2
- import { ElementAnimate } from "./ElementAnimate";
3
- import { GlobalData } from "./GlobalData";
4
- import { OriginPrototype } from "./OriginPrototype";
5
- import type {
6
- DOMUtils_Event,
7
- DOMUtils_EventType,
8
- DOMUtilsAddEventListenerResult,
9
- DOMUtilsDoubleClickOption,
10
- DOMUtilsElementEventType,
11
- DOMUtilsEventListenerOption,
12
- DOMUtilsEventListenerOptionsAttribute,
13
- } from "./types/DOMUtilsEvent";
14
- import type { DOMUtilsTargetElementType } from "./types/global";
15
- import type { WindowApiOption } from "./types/WindowApi";
16
- import { WindowApi } from "./WindowApi";
17
-
18
- class ElementEvent extends ElementAnimate {
19
- windowApi: typeof WindowApi.prototype;
20
- constructor(windowApiOption?: WindowApiOption) {
21
- super(windowApiOption);
22
- this.windowApi = new WindowApi(windowApiOption);
23
- }
24
- /** 获取 animationend 在各个浏览器的兼容名 */
25
- getAnimationEndNameList() {
26
- return CommonUtils.getAnimationEndNameList();
27
- }
28
- /** 获取 transitionend 在各个浏览器的兼容名 */
29
- getTransitionEndNameList() {
30
- return CommonUtils.getTransitionEndNameList();
31
- }
32
- /**
33
- * 绑定事件
34
- * @param element 需要绑定的元素|元素数组|window
35
- * @param eventType 需要监听的事件
36
- * @param handler 绑定事件触发的回调函数
37
- * @param option
38
- * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
39
- * + once 表示事件是否只触发一次。默认为false
40
- * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
41
- * @example
42
- * // 监听元素a.xx的click事件
43
- * DOMUtils.on(document.querySelector("a.xx"),"click",(event)=>{
44
- * console.log("事件触发",event)
45
- * })
46
- * DOMUtils.on("a.xx","click",(event)=>{
47
- * console.log("事件触发",event)
48
- * })
49
- */
50
- on<T extends DOMUtils_EventType>(
51
- element: DOMUtilsElementEventType,
52
- eventType: T | T[],
53
- handler: <E extends HTMLElement = HTMLElement>(this: E, event: DOMUtils_Event[T]) => void,
54
- option?: DOMUtilsEventListenerOption | boolean
55
- ): DOMUtilsAddEventListenerResult;
56
- /**
57
- * 绑定事件
58
- * @param element 需要绑定的元素|元素数组|window
59
- * @param eventType 需要监听的事件
60
- * @param handler 绑定事件触发的回调函数
61
- * @param option
62
- * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
63
- * + once 表示事件是否只触发一次。默认为false
64
- * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
65
- * @example
66
- * // 监听元素a.xx的click事件
67
- * DOMUtils.on(document.querySelector("a.xx"),"click",(event)=>{
68
- * console.log("事件触发",event)
69
- * })
70
- * DOMUtils.on("a.xx","click",(event)=>{
71
- * console.log("事件触发",event)
72
- * })
73
- */
74
- on<T extends Event>(
75
- element: DOMUtilsElementEventType,
76
- eventType: string | string[],
77
- handler: <E extends HTMLElement = HTMLElement>(this: E, event: T) => void,
78
- option?: DOMUtilsEventListenerOption | boolean
79
- ): DOMUtilsAddEventListenerResult;
80
- /**
81
- * 绑定事件
82
- * @param element 需要绑定的元素|元素数组|window
83
- * @param eventType 需要监听的事件
84
- * @param selector 子元素选择器
85
- * @param handler 绑定事件触发的回调函数
86
- * @param option
87
- * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
88
- * + once 表示事件是否只触发一次。默认为false
89
- * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
90
- * @example
91
- * // 监听元素a.xx的click、tap、hover事件
92
- * DOMUtils.on(document.querySelector("a.xx"),"click tap hover",(event, $selector)=>{
93
- * console.log("事件触发", event, $selector)
94
- * })
95
- * DOMUtils.on("a.xx",["click","tap","hover"],(event, $selector)=>{
96
- * console.log("事件触发", event, $selector)
97
- * })
98
- * @example
99
- * // 监听全局document下的子元素a.xx的click事件
100
- * DOMUtils.on(document,"click tap hover","a.xx",(event, $selector)=>{
101
- * console.log("事件触发", event, $selector)
102
- * })
103
- */
104
- on<T extends DOMUtils_EventType>(
105
- element: DOMUtilsElementEventType,
106
- eventType: T | T[],
107
- selector: string | string[] | undefined | null,
108
- handler: <E extends HTMLElement = HTMLElement>(this: E, event: DOMUtils_Event[T], $selector: E) => void,
109
- option?: DOMUtilsEventListenerOption | boolean
110
- ): DOMUtilsAddEventListenerResult;
111
- /**
112
- * 绑定事件
113
- * @param element 需要绑定的元素|元素数组|window
114
- * @param eventType 需要监听的事件
115
- * @param selector 子元素选择器
116
- * @param handler 绑定事件触发的回调函数
117
- * @param option
118
- * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
119
- * + once 表示事件是否只触发一次。默认为false
120
- * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
121
- * @example
122
- * // 监听元素a.xx的click、tap、hover事件
123
- * DOMUtils.on(document.querySelector("a.xx"),"click tap hover",(event, $selector)=>{
124
- * console.log("事件触发", event, $selector)
125
- * })
126
- * DOMUtils.on("a.xx",["click","tap","hover"],(event, $selector)=>{
127
- * console.log("事件触发", event, $selector)
128
- * })
129
- * @example
130
- * // 监听全局document下的子元素a.xx的click事件
131
- * DOMUtils.on(document,"click tap hover","a.xx",(event, $selector)=>{
132
- * console.log("事件触发", event, $selector)
133
- * })
134
- */
135
- on<T extends Event>(
136
- element: DOMUtilsElementEventType,
137
- eventType: string | string[],
138
- selector: string | string[] | undefined | null,
139
- handler: <E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void,
140
- option?: DOMUtilsEventListenerOption | boolean
141
- ): DOMUtilsAddEventListenerResult;
142
- on<T extends Event>(
143
- element: HTMLElement | string | NodeList | HTMLElement[] | Window | Document | Element | null | typeof globalThis,
144
- eventType: DOMUtils_EventType | DOMUtils_EventType[] | string | string[],
145
- selector:
146
- | string
147
- | string[]
148
- | undefined
149
- | (<E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void)
150
- | null,
151
- callback?:
152
- | (<E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void)
153
- | DOMUtilsEventListenerOption
154
- | boolean,
155
- option?: DOMUtilsEventListenerOption | boolean
156
- ): DOMUtilsAddEventListenerResult {
157
- /**
158
- * 获取option配置
159
- * @param args
160
- * @param startIndex
161
- * @param option
162
- */
163
- function getOption(args: IArguments, startIndex: number, option: DOMUtilsEventListenerOption) {
164
- const currentParam = args[startIndex];
165
- if (typeof currentParam === "boolean") {
166
- option.capture = currentParam;
167
- if (typeof args[startIndex + 1] === "boolean") {
168
- option.once = args[startIndex + 1];
169
- }
170
- if (typeof args[startIndex + 2] === "boolean") {
171
- option.passive = args[startIndex + 2];
172
- }
173
- } else if (
174
- typeof currentParam === "object" &&
175
- ("capture" in currentParam ||
176
- "once" in currentParam ||
177
- "passive" in currentParam ||
178
- "isComposedPath" in currentParam)
179
- ) {
180
- option.capture = currentParam.capture;
181
- option.once = currentParam.once;
182
- option.passive = currentParam.passive;
183
- option.isComposedPath = currentParam.isComposedPath;
184
- }
185
- return option;
186
- }
187
-
188
- const that = this;
189
- // eslint-disable-next-line prefer-rest-params
190
- const args = arguments;
191
- if (typeof element === "string") {
192
- element = that.selectorAll(element);
193
- }
194
- if (element == null) {
195
- return {
196
- off() {},
197
- emit() {},
198
- };
199
- }
200
- let $elList: (Element | Document | Window)[] = [];
201
- if (element instanceof NodeList || Array.isArray(element)) {
202
- $elList = $elList.concat(Array.from(element as Element[]));
203
- } else {
204
- $elList.push(element as Element);
205
- }
206
- // 事件名
207
- let eventTypeList: string[] = [];
208
- if (Array.isArray(eventType)) {
209
- eventTypeList = eventTypeList.concat(eventType.filter((it) => typeof it === "string" && it.toString() !== ""));
210
- } else if (typeof eventType === "string") {
211
- eventTypeList = eventTypeList.concat(eventType.split(" ").filter((it) => it !== ""));
212
- }
213
- // 子元素选择器
214
- let selectorList: string[] = [];
215
- if (Array.isArray(selector)) {
216
- selectorList = selectorList.concat(selector.filter((it) => typeof it === "string" && it.toString() !== ""));
217
- } else if (typeof selector === "string") {
218
- selectorList.push(selector);
219
- }
220
- // 事件回调
221
- let listenerCallBack: (this: HTMLElement, event: Event, $selector?: HTMLElement) => void = callback as any;
222
- // 事件配置
223
- let listenerOption: DOMUtilsEventListenerOption = {
224
- capture: false,
225
- once: false,
226
- passive: false,
227
- isComposedPath: false,
228
- };
229
- if (typeof selector === "function") {
230
- // 这是为没有selector的情况
231
- // 那么它就是callback
232
- listenerCallBack = selector as any;
233
- listenerOption = getOption(args, 3, listenerOption);
234
- } else {
235
- // 这是存在selector的情况
236
- listenerOption = getOption(args, 4, listenerOption);
237
- }
238
- /**
239
- * 如果是once,那么删除该监听和元素上的事件和监听
240
- */
241
- const checkOptionOnceToRemoveEventListener = () => {
242
- if (listenerOption.once) {
243
- that.off(element, eventType as any, selector as any, callback as any, option);
244
- }
245
- };
246
- $elList.forEach((elementItem) => {
247
- /**
248
- * 事件回调
249
- * @param event
250
- */
251
- const handlerCallBack = function (event: Event) {
252
- if (selectorList.length) {
253
- /* 存在子元素选择器 */
254
- // 这时候的this和target都是子元素选择器的元素
255
- let eventTarget = listenerOption.isComposedPath
256
- ? (event.composedPath()[0] as HTMLElement)
257
- : (event.target as HTMLElement);
258
- let totalParent = elementItem;
259
- if (CommonUtils.isWin(totalParent)) {
260
- if (totalParent === (that.windowApi.document as any as HTMLElement)) {
261
- totalParent = that.windowApi.document.documentElement;
262
- }
263
- }
264
- const findValue = selectorList.find((selectorItem) => {
265
- // 判断目标元素是否匹配选择器
266
- if (that.matches(eventTarget, selectorItem)) {
267
- /* 当前目标可以被selector所匹配到 */
268
- return true;
269
- }
270
- /* 在上层与主元素之间寻找可以被selector所匹配到的 */
271
- const $closestMatches = that.closest<HTMLElement>(eventTarget, selectorItem);
272
- if ($closestMatches && (<HTMLElement>totalParent)?.contains?.($closestMatches)) {
273
- eventTarget = $closestMatches;
274
- return true;
275
- }
276
- return false;
277
- });
278
- if (findValue) {
279
- // 这里尝试使用defineProperty修改event的target值
280
- try {
281
- OriginPrototype.Object.defineProperty(event, "target", {
282
- get() {
283
- return eventTarget;
284
- },
285
- });
286
- } catch {
287
- // TODO
288
- }
289
- listenerCallBack.call(eventTarget, event as any, eventTarget);
290
- checkOptionOnceToRemoveEventListener();
291
- }
292
- } else {
293
- // 这时候的this指向监听的元素
294
- listenerCallBack.call(elementItem as HTMLElement, event as any);
295
- checkOptionOnceToRemoveEventListener();
296
- }
297
- };
298
-
299
- /* 遍历事件名设置元素事件 */
300
- eventTypeList.forEach((eventName) => {
301
- elementItem.addEventListener(eventName, handlerCallBack, listenerOption);
302
- /* 获取对象上的事件 */
303
- const elementEvents: {
304
- [k: string]: DOMUtilsEventListenerOptionsAttribute[];
305
- } = Reflect.get(elementItem, GlobalData.domEventSymbol) || {};
306
- /* 初始化对象上的xx事件 */
307
- elementEvents[eventName] = elementEvents[eventName] || [];
308
- elementEvents[eventName].push({
309
- selector: selectorList,
310
- option: listenerOption,
311
- handlerCallBack: handlerCallBack,
312
- callback: listenerCallBack,
313
- });
314
- /* 覆盖事件 */
315
- Reflect.set(elementItem, GlobalData.domEventSymbol, elementEvents);
316
- });
317
- });
318
-
319
- return {
320
- /**
321
- * 取消绑定的监听事件
322
- * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
323
- */
324
- off: (
325
- filter?: (
326
- value: DOMUtilsEventListenerOptionsAttribute,
327
- index: number,
328
- array: DOMUtilsEventListenerOptionsAttribute[]
329
- ) => boolean
330
- ) => {
331
- that.off($elList, eventTypeList, selectorList, listenerCallBack, listenerOption, filter);
332
- },
333
- /**
334
- * 主动触发事件
335
- * @param extraDetails 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
336
- * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用callback,但是这种会让使用了$selector的没有值
337
- */
338
- emit: (extraDetails?: object, useDispatchToTriggerEvent?: boolean) => {
339
- that.emit($elList, eventTypeList, extraDetails, useDispatchToTriggerEvent);
340
- },
341
- };
342
- }
343
- /**
344
- * 取消绑定事件
345
- * @param element 需要取消绑定的元素|元素数组
346
- * @param eventType 需要取消监听的事件
347
- * @param callback 通过DOMUtils.on绑定的事件函数
348
- * @param option
349
- * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
350
- * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
351
- * @example
352
- * // 取消监听元素a.xx所有的click事件
353
- * DOMUtils.off(document.querySelector("a.xx"),"click")
354
- * DOMUtils.off("a.xx","click")
355
- */
356
- off<T extends DOMUtils_EventType>(
357
- element: DOMUtilsElementEventType,
358
- eventType: T | T[],
359
- callback?: <E extends HTMLElement = HTMLElement>(this: E, event: DOMUtils_Event[T]) => void,
360
- option?: EventListenerOptions | boolean,
361
- filter?: (
362
- value: DOMUtilsEventListenerOptionsAttribute,
363
- index: number,
364
- array: DOMUtilsEventListenerOptionsAttribute[]
365
- ) => boolean
366
- ): void;
367
- /**
368
- * 取消绑定事件
369
- * @param element 需要取消绑定的元素|元素数组
370
- * @param eventType 需要取消监听的事件
371
- * @param callback 通过DOMUtils.on绑定的事件函数
372
- * @param option
373
- * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
374
- * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
375
- * @example
376
- * // 取消监听元素a.xx的click事件
377
- * DOMUtils.off(document.querySelector("a.xx"),"click")
378
- * DOMUtils.off("a.xx","click")
379
- */
380
- off<T extends Event>(
381
- element: DOMUtilsElementEventType,
382
- eventType: string | string[],
383
- callback?: <E extends HTMLElement = HTMLElement>(this: E, event: T) => void,
384
- option?: EventListenerOptions | boolean,
385
- filter?: (
386
- value: DOMUtilsEventListenerOptionsAttribute,
387
- index: number,
388
- array: DOMUtilsEventListenerOptionsAttribute[]
389
- ) => boolean
390
- ): void;
391
- /**
392
- * 取消绑定事件
393
- * @param element 需要取消绑定的元素|元素数组
394
- * @param eventType 需要取消监听的事件
395
- * @param selector 子元素选择器
396
- * @param callback 通过DOMUtils.on绑定的事件函数
397
- * @param option
398
- * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
399
- * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
400
- * @example
401
- * // 取消监听元素a.xx的click、tap、hover事件
402
- * DOMUtils.off(document.querySelector("a.xx"),"click tap hover")
403
- * DOMUtils.off("a.xx",["click","tap","hover"])
404
- */
405
- off<T extends DOMUtils_EventType>(
406
- element: DOMUtilsElementEventType,
407
- eventType: T | T[],
408
- selector?: string | string[] | undefined | null,
409
- callback?: <E extends HTMLElement = HTMLElement>(this: E, event: DOMUtils_Event[T], $selector: E) => void,
410
- option?: EventListenerOptions | boolean,
411
- filter?: (
412
- value: DOMUtilsEventListenerOptionsAttribute,
413
- index: number,
414
- array: DOMUtilsEventListenerOptionsAttribute[]
415
- ) => boolean
416
- ): void;
417
- /**
418
- * 取消绑定事件
419
- * @param element 需要取消绑定的元素|元素数组
420
- * @param eventType 需要取消监听的事件
421
- * @param selector 子元素选择器
422
- * @param callback 通过DOMUtils.on绑定的事件函数
423
- * @param option
424
- * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
425
- * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
426
- * @example
427
- * // 取消监听元素a.xx的click、tap、hover事件
428
- * DOMUtils.off(document.querySelector("a.xx"),"click tap hover")
429
- * DOMUtils.off("a.xx",["click","tap","hover"])
430
- */
431
- off<T extends Event>(
432
- element: DOMUtilsElementEventType,
433
- eventType: string | string[],
434
- selector?: string | string[] | undefined | null,
435
- callback?: <E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void,
436
- option?: EventListenerOptions | boolean,
437
- filter?: (
438
- value: DOMUtilsEventListenerOptionsAttribute,
439
- index: number,
440
- array: DOMUtilsEventListenerOptionsAttribute[]
441
- ) => boolean
442
- ): void;
443
- off<T extends Event>(
444
- element: HTMLElement | string | NodeList | HTMLElement[] | Window | Document | Element | null | typeof globalThis,
445
- eventType: DOMUtils_EventType | DOMUtils_EventType[] | string | string[],
446
- selector:
447
- | string
448
- | string[]
449
- | undefined
450
- | (<E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void)
451
- | null,
452
- callback?:
453
- | (<E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void)
454
- | EventListenerOptions
455
- | boolean,
456
- option?:
457
- | EventListenerOptions
458
- | boolean
459
- | ((
460
- value: DOMUtilsEventListenerOptionsAttribute,
461
- index: number,
462
- array: DOMUtilsEventListenerOptionsAttribute[]
463
- ) => boolean),
464
- filter?: (
465
- value: DOMUtilsEventListenerOptionsAttribute,
466
- index: number,
467
- array: DOMUtilsEventListenerOptionsAttribute[]
468
- ) => boolean
469
- ) {
470
- /**
471
- * 获取option配置
472
- * @param args1
473
- * @param startIndex
474
- * @param option
475
- */
476
- function getOption(args1: IArguments, startIndex: number, option: EventListenerOptions) {
477
- const currentParam: EventListenerOptions | boolean = args1[startIndex];
478
- if (typeof currentParam === "boolean") {
479
- option.capture = currentParam;
480
- } else if (typeof currentParam === "object" && currentParam != null && "capture" in currentParam) {
481
- option.capture = currentParam.capture;
482
- }
483
- return option;
484
- }
485
- const that = this;
486
- // eslint-disable-next-line prefer-rest-params
487
- const args = arguments;
488
- if (typeof element === "string") {
489
- element = that.selectorAll(element);
490
- }
491
- if (element == null) {
492
- return;
493
- }
494
- let $elList: HTMLElement[] = [];
495
- if (element instanceof NodeList || Array.isArray(element)) {
496
- element = element as HTMLElement[];
497
- $elList = $elList.concat(Array.from(element));
498
- } else {
499
- $elList.push(element as HTMLElement);
500
- }
501
- let eventTypeList: string[] = [];
502
- if (Array.isArray(eventType)) {
503
- eventTypeList = eventTypeList.concat(eventType.filter((it) => typeof it === "string" && it.toString() !== ""));
504
- } else if (typeof eventType === "string") {
505
- eventTypeList = eventTypeList.concat(eventType.split(" ").filter((it) => it !== ""));
506
- }
507
- // 子元素选择器
508
- let selectorList: string[] = [];
509
- if (Array.isArray(selector)) {
510
- selectorList = selectorList.concat(selector.filter((it) => typeof it === "string" && it.toString() !== ""));
511
- } else if (typeof selector === "string") {
512
- selectorList.push(selector);
513
- }
514
- /**
515
- * 事件的回调函数
516
- */
517
- let listenerCallBack: (this: HTMLElement, event: T, $selector: HTMLElement) => void = callback as any;
518
-
519
- /**
520
- * 事件的配置
521
- */
522
- let listenerOption: EventListenerOptions = {
523
- capture: false,
524
- };
525
- if (typeof selector === "function") {
526
- // 这是为没有selector的情况
527
- // 那么它就是callback
528
- listenerCallBack = selector;
529
- listenerOption = getOption(args, 3, listenerOption);
530
- } else {
531
- // 这是存在selector的情况
532
- listenerOption = getOption(args, 4, listenerOption);
533
- }
534
- // 是否移除所有事件
535
- let isRemoveAll = false;
536
- if (args.length === 2) {
537
- // 目标函数、事件名
538
- isRemoveAll = true;
539
- } else if ((args.length === 3 && typeof args[2] === "string") || Array.isArray(args[2])) {
540
- // 目标函数、事件名、子元素选择器
541
- isRemoveAll = true;
542
- }
543
- if (args.length === 5 && typeof args[4] === "function" && typeof filter !== "function") {
544
- // 目标函数、事件名、回调函数、事件配置、过滤函数
545
- filter = option as (
546
- value: DOMUtilsEventListenerOptionsAttribute,
547
- index: number,
548
- array: DOMUtilsEventListenerOptionsAttribute[]
549
- ) => boolean;
550
- }
551
- $elList.forEach(($elItem) => {
552
- /* 获取对象上的事件 */
553
- const elementEvents: {
554
- [key: string]: DOMUtilsEventListenerOptionsAttribute[];
555
- } = Reflect.get($elItem, GlobalData.domEventSymbol) || {};
556
- eventTypeList.forEach((eventName) => {
557
- const handlers = elementEvents[eventName] || [];
558
- const filterHandler = typeof filter === "function" ? handlers.filter(filter) : handlers;
559
- for (let index = 0; index < filterHandler.length; index++) {
560
- const handler = filterHandler[index];
561
- let flag = true;
562
- if (flag && listenerCallBack && handler.callback !== listenerCallBack) {
563
- // callback不同
564
- flag = false;
565
- }
566
- if (flag && selectorList.length && Array.isArray(handler.selector)) {
567
- if (JSON.stringify(handler.selector) !== JSON.stringify(selectorList)) {
568
- // 子元素选择器不同
569
- flag = false;
570
- }
571
- }
572
- if (
573
- flag &&
574
- typeof handler.option.capture === "boolean" &&
575
- listenerOption.capture !== handler.option.capture
576
- ) {
577
- // 事件的配置项不同
578
- flag = false;
579
- }
580
- if (flag || isRemoveAll) {
581
- $elItem.removeEventListener(eventName, handler.handlerCallBack, handler.option);
582
- const findIndex = handlers.findIndex((item) => item === handler);
583
- if (findIndex !== -1) {
584
- handlers.splice(findIndex, 1);
585
- }
586
- }
587
- }
588
- if (handlers.length === 0) {
589
- /* 如果没有任意的handler,那么删除该属性 */
590
- CommonUtils.delete(elementEvents, eventType);
591
- }
592
- });
593
- Reflect.set($elItem, GlobalData.domEventSymbol, elementEvents);
594
- });
595
- }
596
- /**
597
- * 取消绑定所有的事件
598
- * @param element 需要取消绑定的元素|元素数组
599
- * @param eventType (可选)需要取消监听的事件
600
- */
601
- offAll(element: DOMUtilsElementEventType, eventType?: string): void;
602
- /**
603
- * 取消绑定所有的事件
604
- * @param element 需要取消绑定的元素|元素数组
605
- * @param eventType (可选)需要取消监听的事件
606
- */
607
- offAll(element: DOMUtilsElementEventType, eventType?: DOMUtils_EventType | DOMUtils_EventType[]): void;
608
- /**
609
- * 取消绑定所有的事件
610
- * @param element 需要取消绑定的元素|元素数组
611
- * @param eventType (可选)需要取消监听的事件
612
- */
613
- offAll(element: DOMUtilsElementEventType, eventType?: DOMUtils_EventType | DOMUtils_EventType[] | string) {
614
- const that = this;
615
- if (typeof element === "string") {
616
- element = that.selectorAll(element);
617
- }
618
- if (element == null) {
619
- return;
620
- }
621
- let $elList: (Element | Document | Window | typeof globalThis | Node | ChildNode | EventTarget)[] = [];
622
- if (element instanceof NodeList || Array.isArray(element)) {
623
- $elList = $elList.concat(Array.from(element as HTMLElement[]));
624
- } else {
625
- $elList.push(element);
626
- }
627
-
628
- let eventTypeList: string[] = [];
629
- if (Array.isArray(eventType)) {
630
- eventTypeList = eventTypeList.concat(eventType as string[]);
631
- } else if (typeof eventType === "string") {
632
- eventTypeList = eventTypeList.concat(eventType.split(" "));
633
- }
634
- $elList.forEach(($elItem) => {
635
- const symbolList = [...new Set([...Object.getOwnPropertySymbols($elItem), GlobalData.domEventSymbol])];
636
- symbolList.forEach((symbolItem) => {
637
- if (!symbolItem.toString().startsWith("Symbol(events_")) {
638
- return;
639
- }
640
- const elementEvents: {
641
- [key: string]: DOMUtilsEventListenerOptionsAttribute[];
642
- } = Reflect.get($elItem, symbolItem) || {};
643
- const iterEventNameList = eventTypeList.length ? eventTypeList : Object.keys(elementEvents);
644
- iterEventNameList.forEach((eventName) => {
645
- const handlers: DOMUtilsEventListenerOptionsAttribute[] = elementEvents[eventName];
646
- if (!handlers) {
647
- return;
648
- }
649
- for (const handler of handlers) {
650
- $elItem.removeEventListener(eventName, handler.handlerCallBack, {
651
- capture: handler.option.capture,
652
- });
653
- }
654
- const events = Reflect.get($elItem, symbolItem);
655
- CommonUtils.delete(events, eventName);
656
- });
657
- });
658
- });
659
- }
660
-
661
- /**
662
- * 等待文档加载完成后执行指定的函数
663
- * @param callback 需要执行的函数
664
- * @example
665
- * DOMUtils.onReady(function(){
666
- * console.log("文档加载完毕")
667
- * });
668
- * > "文档加载完毕"
669
- * @example
670
- * await DOMUtils.onReady();
671
- * console.log("文档加载完毕");
672
- * > "文档加载完毕"
673
- */
674
- onReady(): Promise<void>;
675
- onReady(callback: (...args: any[]) => any): void;
676
- onReady(...args: any[]): void | Promise<void> {
677
- const callback: ((...args: any[]) => any) | undefined = args[0];
678
- // 异步回调
679
- let resolve: ((...args: any[]) => any) | undefined = void 0;
680
- const that = this;
681
- /**
682
- * 监听目标
683
- */
684
- const listenTargetList = [
685
- {
686
- target: that.windowApi.document,
687
- eventType: "DOMContentLoaded",
688
- callback: () => {
689
- ReadyChecker.completed();
690
- },
691
- },
692
- {
693
- target: that.windowApi.window,
694
- eventType: "load",
695
- callback: () => {
696
- ReadyChecker.completed();
697
- },
698
- },
699
- ];
700
- const ReadyChecker = {
701
- init() {
702
- if (args.length === 0) {
703
- return new Promise<void>((__resolve__) => {
704
- resolve = __resolve__;
705
- ReadyChecker.check();
706
- });
707
- } else {
708
- ReadyChecker.check();
709
- }
710
- },
711
- check() {
712
- if (ReadyChecker.isReady()) {
713
- /* 检查document状态 */
714
- setTimeout(() => {
715
- ReadyChecker.completed();
716
- }, 0);
717
- } else {
718
- /* 添加监听 */
719
- ReadyChecker.onCompleted();
720
- }
721
- },
722
- /**
723
- * 检测文档是否加载完毕
724
- */
725
- isReady() {
726
- try {
727
- if (
728
- that.windowApi.document.readyState === "complete" ||
729
- // @ts-expect-error
730
- (that.windowApi.document.readyState !== "loading" && !that.windowApi.document.documentElement.doScroll)
731
- ) {
732
- return true;
733
- } else {
734
- return false;
735
- }
736
- } catch {
737
- return false;
738
- }
739
- },
740
- /**
741
- * 成功加载完毕后触发的回调函数
742
- */
743
- completed() {
744
- ReadyChecker.offCompleted();
745
- if (typeof callback === "function") {
746
- callback();
747
- }
748
- if (typeof resolve === "function") {
749
- resolve();
750
- }
751
- },
752
- /**
753
- * 添加监听
754
- */
755
- onCompleted() {
756
- for (const item of listenTargetList) {
757
- that.on(item.target, item.eventType, item.callback);
758
- }
759
- },
760
- /**
761
- * 移除监听
762
- */
763
- offCompleted() {
764
- for (const item of listenTargetList) {
765
- that.off(item.target, item.eventType, item.callback);
766
- }
767
- },
768
- };
769
-
770
- return ReadyChecker.init();
771
- }
772
- /**
773
- * 主动触发事件
774
- * @param element 需要触发的元素|元素数组|window
775
- * @param eventType 需要触发的事件
776
- * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用通过.on监听的callback,但是这种会让使用了$selector的没有值
777
- * @example
778
- * // 触发元素a.xx的click事件
779
- * DOMUtils.emit(document.querySelector("a.xx"),"click")
780
- * DOMUtils.emit("a.xx","click")
781
- * // 触发元素a.xxclick、tap、hover事件
782
- * DOMUtils.emit(document.querySelector("a.xx"),"click tap hover")
783
- * DOMUtils.emit("a.xx",["click","tap","hover"])
784
- */
785
- emit(
786
- element: DOMUtilsTargetElementType | Element | DocumentFragment | any[] | typeof globalThis | Window | Document,
787
- eventType: string | string[],
788
- useDispatchToTriggerEvent?: boolean
789
- ): void;
790
- /**
791
- * 主动触发事件
792
- * @param element 需要触发的元素|元素数组|window
793
- * @param eventType 需要触发的事件
794
- * @param extraDetails 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
795
- * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用通过.on监听的callback(),但是这种只有一个入参,如果使用$selector则没有值
796
- * @example
797
- * // 触发元素a.xx的click事件
798
- * DOMUtils.emit(document.querySelector("a.xx"),"click")
799
- * DOMUtils.emit("a.xx","click")
800
- * // 触发元素a.xxclick、tap、hover事件
801
- * DOMUtils.emit(document.querySelector("a.xx"),"click tap hover")
802
- * DOMUtils.emit("a.xx",["click","tap","hover"])
803
- */
804
- emit(
805
- element: DOMUtilsTargetElementType | Element | DocumentFragment | any[] | typeof globalThis | Window | Document,
806
- eventType: string | string[],
807
- extraDetails?: object,
808
- useDispatchToTriggerEvent?: boolean
809
- ): void;
810
- /**
811
- * 主动触发事件
812
- * @param element 需要触发的元素|元素数组|window
813
- * @param eventType 需要触发的事件
814
- * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用通过.on监听的callback(),但是这种只有一个入参,如果使用$selector则没有值
815
- * @example
816
- * // 触发元素a.xx的click事件
817
- * DOMUtils.emit(document.querySelector("a.xx"),"click")
818
- * DOMUtils.emit("a.xx","click")
819
- * // 触发元素a.xxclick、tap、hover事件
820
- * DOMUtils.emit(document.querySelector("a.xx"),"click tap hover")
821
- * DOMUtils.emit("a.xx",["click","tap","hover"])
822
- */
823
- emit(
824
- element: Element | string | NodeList | any[] | Window | Document,
825
- eventType: DOMUtils_EventType | DOMUtils_EventType[],
826
- useDispatchToTriggerEvent?: boolean
827
- ): void;
828
- /**
829
- * 主动触发事件
830
- * @param element 需要触发的元素|元素数组|window
831
- * @param eventType 需要触发的事件
832
- * @param extraDetails 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
833
- * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用通过.on监听的callback(),但是这种只有一个入参,如果使用$selector则没有值
834
- * @example
835
- * // 触发元素a.xx的click事件
836
- * DOMUtils.emit(document.querySelector("a.xx"),"click")
837
- * DOMUtils.emit("a.xx","click")
838
- * // 触发元素a.xxclick、tap、hover事件
839
- * DOMUtils.emit(document.querySelector("a.xx"),"click tap hover")
840
- * DOMUtils.emit("a.xx",["click","tap","hover"])
841
- */
842
- emit(
843
- element: Element | string | NodeList | any[] | Window | Document,
844
- eventType: DOMUtils_EventType | DOMUtils_EventType[],
845
- extraDetails?: object,
846
- useDispatchToTriggerEvent?: boolean
847
- ): void;
848
- /**
849
- * 主动触发事件
850
- * @param element 需要触发的元素|元素数组|window
851
- * @param eventType 需要触发的事件
852
- * @param extraDetails 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
853
- * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用通过.on监听的callback(),但是这种只有一个入参,如果使用$selector则没有值
854
- * @example
855
- * // 触发元素a.xx的click事件
856
- * DOMUtils.emit(document.querySelector("a.xx"),"click")
857
- * DOMUtils.emit("a.xx","click")
858
- * // 触发元素a.xxclick、tap、hover事件
859
- * DOMUtils.emit(document.querySelector("a.xx"),"click tap hover")
860
- * DOMUtils.emit("a.xx",["click","tap","hover"])
861
- */
862
- emit(
863
- element: Element | string | NodeList | any[] | Window | Document,
864
- eventType: DOMUtils_EventType | DOMUtils_EventType[] | string | string[],
865
- extraDetails?: object | boolean,
866
- useDispatchToTriggerEvent: boolean = true
867
- ) {
868
- const that = this;
869
- if (typeof element === "string") {
870
- element = that.selectorAll(element);
871
- }
872
- if (element == null) {
873
- return;
874
- }
875
- let $elList: (Document | Window | Element)[] = [];
876
- if (element instanceof NodeList || Array.isArray(element)) {
877
- $elList = $elList.concat(Array.from(element));
878
- } else {
879
- $elList.push(element);
880
- }
881
- let eventTypeList: string[] = [];
882
- if (Array.isArray(eventType)) {
883
- eventTypeList = eventType.filter((it) => typeof it === "string" && it.trim() !== "");
884
- } else if (typeof eventType === "string") {
885
- eventTypeList = eventType.split(" ");
886
- }
887
-
888
- $elList.forEach(($elItem) => {
889
- /* 获取对象上的事件 */
890
- const elementEvents: {
891
- [key: string]: DOMUtilsEventListenerOptionsAttribute[];
892
- } = Reflect.get($elItem, GlobalData.domEventSymbol) || {};
893
- eventTypeList.forEach((eventTypeItem) => {
894
- let event: Event = null as any;
895
- if (extraDetails && extraDetails instanceof Event) {
896
- event = extraDetails;
897
- } else {
898
- // 构造事件
899
- event = new Event(eventTypeItem);
900
- if (typeof extraDetails === "object" && extraDetails != null) {
901
- const detailKeys = Object.keys(extraDetails);
902
- detailKeys.forEach((keyName) => {
903
- const value = Reflect.get(extraDetails, keyName);
904
- // 在event上添加属性
905
- Reflect.set(event, keyName, value);
906
- });
907
- }
908
- }
909
- if (useDispatchToTriggerEvent == false && eventTypeItem in elementEvents) {
910
- // 直接调用监听的事件
911
- elementEvents[eventTypeItem].forEach((eventsItem) => {
912
- eventsItem.handlerCallBack(event);
913
- });
914
- } else {
915
- $elItem.dispatchEvent(event);
916
- }
917
- });
918
- });
919
- }
920
-
921
- /**
922
- * 监听或触发元素的click事件
923
- * @param element 目标元素
924
- * @param handler (可选)事件处理函数
925
- * @param details (可选)赋予触发的Event的额外属性
926
- * @param useDispatchToEmit (可选)是否使用dispatchEvent来触发事件,默认true
927
- * @example
928
- * // 触发元素a.xx的click事件
929
- * DOMUtils.click(document.querySelector("a.xx"))
930
- * DOMUtils.click("a.xx")
931
- * DOMUtils.click("a.xx",function(){
932
- * console.log("触发click事件成功")
933
- * })
934
- * */
935
- click(
936
- element: DOMUtilsTargetElementType | Element | DocumentFragment | typeof globalThis | Window,
937
- handler?: (this: HTMLElement, event: DOMUtils_Event["click"]) => void,
938
- details?: object,
939
- useDispatchToEmit?: boolean
940
- ) {
941
- const that = this;
942
- if (typeof element === "string") {
943
- element = that.selectorAll(element);
944
- }
945
- if (element == null) {
946
- return;
947
- }
948
- if (CommonUtils.isNodeList(element)) {
949
- // 设置
950
- element.forEach(($ele) => {
951
- that.click($ele as HTMLElement, handler, details, useDispatchToEmit);
952
- });
953
- return;
954
- }
955
- if (handler == null) {
956
- that.emit(element, "click", details, useDispatchToEmit);
957
- } else {
958
- that.on(element, "click", null, handler);
959
- }
960
- }
961
- /**
962
- * 监听或触发元素的blur事件
963
- * @param element 目标元素
964
- * @param handler (可选)事件处理函数
965
- * @param details (可选)赋予触发的Event的额外属性
966
- * @param useDispatchToEmit (可选)是否使用dispatchEvent来触发事件,默认true
967
- * @example
968
- * // 触发元素a.xx的blur事件
969
- * DOMUtils.blur(document.querySelector("a.xx"))
970
- * DOMUtils.blur("a.xx")
971
- * DOMUtils.blur("a.xx",function(){
972
- * console.log("触发blur事件成功")
973
- * })
974
- * */
975
- blur(
976
- element: DOMUtilsTargetElementType | Element | DocumentFragment | typeof globalThis | Window,
977
- handler?: (this: HTMLElement, event: DOMUtils_Event["blur"]) => void,
978
- details?: object,
979
- useDispatchToEmit?: boolean
980
- ) {
981
- const that = this;
982
- if (typeof element === "string") {
983
- element = that.selectorAll(element);
984
- }
985
- if (element == null) {
986
- return;
987
- }
988
- if (CommonUtils.isNodeList(element)) {
989
- // 设置
990
- element.forEach(($ele) => {
991
- that.focus($ele as HTMLElement, handler, details, useDispatchToEmit);
992
- });
993
- return;
994
- }
995
- if (handler === null) {
996
- that.emit(element, "blur", details, useDispatchToEmit);
997
- } else {
998
- that.on(element, "blur", null, handler as (event: Event) => void);
999
- }
1000
- }
1001
- /**
1002
- * 监听或触发元素的focus事件
1003
- * @param element 目标元素
1004
- * @param handler (可选)事件处理函数
1005
- * @param details (可选)赋予触发的Event的额外属性
1006
- * @param useDispatchToEmit (可选)是否使用dispatchEvent来触发事件,默认true
1007
- * @example
1008
- * // 触发元素a.xx的focus事件
1009
- * DOMUtils.focus(document.querySelector("a.xx"))
1010
- * DOMUtils.focus("a.xx")
1011
- * DOMUtils.focus("a.xx",function(){
1012
- * console.log("触发focus事件成功")
1013
- * })
1014
- * */
1015
- focus(
1016
- element: DOMUtilsTargetElementType | Element | DocumentFragment | typeof globalThis | Window,
1017
- handler?: (this: HTMLElement, event: DOMUtils_Event["focus"]) => void,
1018
- details?: object,
1019
- useDispatchToEmit?: boolean
1020
- ) {
1021
- const that = this;
1022
- if (typeof element === "string") {
1023
- element = that.selectorAll(element);
1024
- }
1025
- if (element == null) {
1026
- return;
1027
- }
1028
- if (CommonUtils.isNodeList(element)) {
1029
- // 设置
1030
- element.forEach(($ele) => {
1031
- that.focus($ele as HTMLElement, handler, details, useDispatchToEmit);
1032
- });
1033
- return;
1034
- }
1035
- if (handler == null) {
1036
- that.emit(element, "focus", details, useDispatchToEmit);
1037
- } else {
1038
- that.on(element, "focus", null, handler);
1039
- }
1040
- }
1041
- /**
1042
- * 当鼠标移入或移出元素时触发事件
1043
- * @param element 当前元素
1044
- * @param handler 事件处理函数
1045
- * @param option 配置
1046
- * @example
1047
- * // 监听a.xx元素的移入或移出
1048
- * DOMUtils.onHover(document.querySelector("a.xx"),()=>{
1049
- * console.log("移入/移除");
1050
- * })
1051
- * DOMUtils.onHover("a.xx",()=>{
1052
- * console.log("移入/移除");
1053
- * })
1054
- */
1055
- onHover(
1056
- element: DOMUtilsTargetElementType | Element | DocumentFragment | Node,
1057
- handler: (this: HTMLElement, event: DOMUtils_Event["hover"]) => void,
1058
- option?: boolean | DOMUtilsEventListenerOption
1059
- ) {
1060
- const that = this;
1061
- if (typeof element === "string") {
1062
- element = that.selectorAll(element);
1063
- }
1064
- if (element == null) {
1065
- return;
1066
- }
1067
- if (CommonUtils.isNodeList(element)) {
1068
- // 设置
1069
- element.forEach(($ele) => {
1070
- that.onHover($ele as HTMLElement, handler, option);
1071
- });
1072
- return;
1073
- }
1074
- that.on(element, "mouseenter", null, handler, option);
1075
- that.on(element, "mouseleave", null, handler, option);
1076
- }
1077
- /**
1078
- * 监听动画结束
1079
- * @param element 监听的元素
1080
- * @param handler 触发的回调函数
1081
- * @param option 配置项,这里默认配置once为true
1082
- */
1083
- onAnimationend(
1084
- element: HTMLElement | string | Element | DocumentFragment,
1085
- handler: (this: HTMLElement, event: DOMUtils_Event["animationend"]) => void,
1086
- option?: boolean | DOMUtilsEventListenerOption
1087
- ) {
1088
- const that = this;
1089
- if (typeof element === "string") {
1090
- element = that.selector(element)!;
1091
- }
1092
- if (element == null) {
1093
- return;
1094
- }
1095
- const defaultOption: DOMUtilsEventListenerOption = {
1096
- once: true,
1097
- };
1098
- Object.assign(defaultOption, option || {});
1099
- const eventNameList = CommonUtils.getAnimationEndNameList();
1100
- that.on(element, eventNameList, null, handler, defaultOption);
1101
- if (!defaultOption.once) {
1102
- return {
1103
- off() {
1104
- that.off(element, eventNameList, null, handler, defaultOption);
1105
- },
1106
- };
1107
- }
1108
- }
1109
- /**
1110
- * 监听过渡结束
1111
- * @param element 监听的元素
1112
- * @param handler 触发的回调函数
1113
- * @param option 配置项,这里默认配置once为true
1114
- */
1115
- onTransitionend(
1116
- element: HTMLElement | string | Element | DocumentFragment,
1117
- handler: (this: HTMLElement, event: DOMUtils_Event["transitionend"]) => void,
1118
- option?: boolean | DOMUtilsEventListenerOption
1119
- ) {
1120
- const that = this;
1121
- if (typeof element === "string") {
1122
- element = that.selector(element)!;
1123
- }
1124
- if (element == null) {
1125
- return;
1126
- }
1127
- const defaultOption: DOMUtilsEventListenerOption = {
1128
- once: true,
1129
- };
1130
- Object.assign(defaultOption, option || {});
1131
- const eventNameList = CommonUtils.getTransitionEndNameList();
1132
- that.on(element, eventNameList, null, handler, defaultOption);
1133
- if (!defaultOption.once) {
1134
- return {
1135
- off() {
1136
- that.off(element, eventNameList, null, handler, defaultOption);
1137
- },
1138
- };
1139
- }
1140
- }
1141
- /**
1142
- * 当按键松开时触发事件
1143
- * keydown - > keypress - > keyup
1144
- * @param element 当前元素
1145
- * @param handler 事件处理函数
1146
- * @param option 配置
1147
- * @example
1148
- * // 监听a.xx元素的按键松开
1149
- * DOMUtils.keyup(document.querySelector("a.xx"),()=>{
1150
- * console.log("按键松开");
1151
- * })
1152
- * DOMUtils.keyup("a.xx",()=>{
1153
- * console.log("按键松开");
1154
- * })
1155
- */
1156
- onKeyup(
1157
- element: DOMUtilsTargetElementType | Element | DocumentFragment | Window | Node | typeof globalThis,
1158
- handler: (this: HTMLElement, event: DOMUtils_Event["keyup"]) => void,
1159
- option?: boolean | DOMUtilsEventListenerOption
1160
- ) {
1161
- const that = this;
1162
- if (element == null) {
1163
- return;
1164
- }
1165
- if (typeof element === "string") {
1166
- element = that.selectorAll(element);
1167
- }
1168
- if (CommonUtils.isNodeList(element)) {
1169
- // 设置
1170
- element.forEach(($ele) => {
1171
- that.onKeyup($ele as HTMLElement, handler, option);
1172
- });
1173
- return;
1174
- }
1175
- that.on(element, "keyup", null, handler, option);
1176
- }
1177
- /**
1178
- * 当按键按下时触发事件
1179
- * keydown - > keypress - > keyup
1180
- * @param element 目标
1181
- * @param handler 事件处理函数
1182
- * @param option 配置
1183
- * @example
1184
- * // 监听a.xx元素的按键按下
1185
- * DOMUtils.keydown(document.querySelector("a.xx"),()=>{
1186
- * console.log("按键按下");
1187
- * })
1188
- * DOMUtils.keydown("a.xx",()=>{
1189
- * console.log("按键按下");
1190
- * })
1191
- */
1192
- onKeydown(
1193
- element: DOMUtilsTargetElementType | Element | DocumentFragment | Window | Node | typeof globalThis,
1194
- handler: (this: HTMLElement, event: DOMUtils_Event["keydown"]) => void,
1195
- option?: boolean | DOMUtilsEventListenerOption
1196
- ) {
1197
- const that = this;
1198
- if (element == null) {
1199
- return;
1200
- }
1201
- if (typeof element === "string") {
1202
- element = that.selectorAll(element);
1203
- }
1204
- if (CommonUtils.isNodeList(element)) {
1205
- // 设置
1206
- element.forEach(($ele) => {
1207
- that.onKeydown($ele as HTMLElement, handler, option);
1208
- });
1209
- return;
1210
- }
1211
- that.on(element, "keydown", null, handler, option);
1212
- }
1213
- /**
1214
- * 当按键按下时触发事件
1215
- * keydown - > keypress - > keyup
1216
- * @param element 目标
1217
- * @param handler 事件处理函数
1218
- * @param option 配置
1219
- * @example
1220
- * // 监听a.xx元素的按键按下
1221
- * DOMUtils.keypress(document.querySelector("a.xx"),()=>{
1222
- * console.log("按键按下");
1223
- * })
1224
- * DOMUtils.keypress("a.xx",()=>{
1225
- * console.log("按键按下");
1226
- * })
1227
- */
1228
- onKeypress(
1229
- element: DOMUtilsTargetElementType | Element | DocumentFragment | Window | Node | typeof globalThis,
1230
- handler: (this: HTMLElement, event: DOMUtils_Event["keypress"]) => void,
1231
- option?: boolean | DOMUtilsEventListenerOption
1232
- ) {
1233
- const that = this;
1234
- if (element == null) {
1235
- return;
1236
- }
1237
- if (typeof element === "string") {
1238
- element = that.selectorAll(element);
1239
- }
1240
- if (CommonUtils.isNodeList(element)) {
1241
- // 设置
1242
- element.forEach(($ele) => {
1243
- that.onKeypress($ele as HTMLElement, handler, option);
1244
- });
1245
- return;
1246
- }
1247
- that.on(element, "keypress", null, handler, option);
1248
- }
1249
- /**
1250
- * 监听某个元素键盘按键事件或window全局按键事件
1251
- * 按下有值的键时触发,按下Ctrl\Alt\Shift\Meta是无值键。按下先触发keydown事件,再触发keypress事件。
1252
- * @param element 需要监听的对象,可以是全局Window或者某个元素
1253
- * @param eventName 事件名,默认keypress,keydown - > keypress - > keyup
1254
- * @param handler 自己定义的回调事件,参数1为当前的key,参数2为组合按键,数组类型,包含ctrl、shift、alt和meta(win键或mac的cmd键)
1255
- * @param options 监听事件的配置
1256
- * @example
1257
- Utils.onKeyboard(window,(keyName,keyValue,otherKey,event)=>{
1258
- if(keyName === "Enter"){
1259
- console.log("回车按键的值是:"+keyValue)
1260
- }
1261
- if(otherKey.indexOf("ctrl") && keyName === "Enter" ){
1262
- console.log("Ctrl和回车键");
1263
- }
1264
- })
1265
- * @example
1266
- 字母和数字键的键码值(keyCode)
1267
- 按键 键码 按键 键码 按键 键码 按键 键码
1268
- A 65 J 74 S 83 1 49
1269
- B 66 K 75 T 84 2 50
1270
- C 67 L 76 U 85 3 51
1271
- D 68 M 77 V 86 4 52
1272
- E 69 N 78 W 87 5 53
1273
- F 70 O 79 X 88 6 54
1274
- G 71 P 80 Y 89 7 55
1275
- H 72 Q 81 Z 90 8 56
1276
- I 73 R 82 0 48 9 57
1277
-
1278
- 数字键盘上的键的键码值(keyCode)
1279
- 功能键键码值(keyCode)
1280
- 按键 键码 按键 键码 按键 键码 按键 键码
1281
- 0 96 8 104 F1 112 F7 118
1282
- 1 97 9 105 F2 113 F8 119
1283
- 2 98 * 106 F3 114 F9 120
1284
- 3 99 + 107 F4 115 F10 121
1285
- 4 100 Enter 108 F5 116 F11 122
1286
- 5 101 - 109 F6 117 F12 123
1287
- 6 102 . 110
1288
- 7 103 / 111
1289
-
1290
- 控制键键码值(keyCode)
1291
- 按键 键码 按键 键码 按键 键码 按键 键码
1292
- BackSpace 8 Esc 27 → 39 -_ 189
1293
- Tab 9 Spacebar 32 ↓ 40 .> 190
1294
- Clear 12 Page Up 33 Insert 45 /? 191
1295
- Enter 13 Page Down 34 Delete 46 `~ 192
1296
- Shift 16 End 35 Num Lock 144 [{ 219
1297
- Control 17 Home 36 ;: 186 \| 220
1298
- Alt 18 37 =+ 187 ]} 221
1299
- Cape Lock 20 ↑ 38 ,< 188 '" 222
1300
-
1301
- 多媒体键码值(keyCode)
1302
- 按键 键码
1303
- 音量加 175
1304
- 音量减 174
1305
- 停止 179
1306
- 静音 173
1307
- 浏览器 172
1308
- 邮件 180
1309
- 搜索 170
1310
- 收藏 171
1311
- **/
1312
- onKeyboard(
1313
- element: DOMUtilsTargetElementType | Element | DocumentFragment | Window | Node | typeof globalThis,
1314
- eventName: "keydown" | "keypress" | "keyup" = "keypress",
1315
- handler: (keyName: string, keyValue: number, otherCodeList: string[], event: KeyboardEvent) => void,
1316
- options?: DOMUtilsEventListenerOption | boolean
1317
- ): {
1318
- removeListen(): void;
1319
- } {
1320
- const that = this;
1321
- if (typeof element === "string") {
1322
- element = that.selectorAll(element);
1323
- }
1324
- const keyboardEventCallBack = function (event: KeyboardEvent) {
1325
- /** 键名 */
1326
- const keyName = event.key || event.code;
1327
- /** 键值 */
1328
- const keyValue = event.charCode || event.keyCode || event.which;
1329
- /** 组合键列表 */
1330
- const otherCodeList: string[] = [];
1331
- if (event.ctrlKey) {
1332
- otherCodeList.push("ctrl");
1333
- }
1334
- if (event.altKey) {
1335
- otherCodeList.push("alt");
1336
- }
1337
- if (event.metaKey) {
1338
- otherCodeList.push("meta");
1339
- }
1340
- if (event.shiftKey) {
1341
- otherCodeList.push("shift");
1342
- }
1343
- if (typeof handler === "function") {
1344
- handler(keyName, keyValue, otherCodeList, event);
1345
- }
1346
- };
1347
- that.on(element, eventName, keyboardEventCallBack, options);
1348
- return {
1349
- removeListen: () => {
1350
- that.off(element, eventName, keyboardEventCallBack, options);
1351
- },
1352
- };
1353
- }
1354
- /**
1355
- * 监input、textarea的输入框值改变的事件(当输入法输入时,不会触发该监听)
1356
- * @param $el 输入框元素
1357
- * @param handler 回调函数
1358
- * @param option 配置
1359
- */
1360
- onInput(
1361
- $el: HTMLInputElement | HTMLTextAreaElement,
1362
- handler: (evt: InputEvent) => void | Promise<void>,
1363
- option?: DOMUtilsEventListenerOption | boolean
1364
- ) {
1365
- /**
1366
- * 是否正在输入中
1367
- */
1368
- let isComposite = false;
1369
- const __callback = async (event: InputEvent) => {
1370
- if (isComposite) return;
1371
- await handler(event);
1372
- };
1373
- const __composition_start_callback = () => {
1374
- isComposite = true;
1375
- };
1376
- const __composition_end_callback = () => {
1377
- isComposite = false;
1378
- this.emit($el, "input", {
1379
- isComposite,
1380
- });
1381
- };
1382
- const inputListener = this.on($el, "input", __callback, option);
1383
- const compositionStartListener = this.on($el, "compositionstart", __composition_start_callback, option);
1384
- const compositionEndListener = this.on($el, "compositionend", __composition_end_callback, option);
1385
-
1386
- return {
1387
- off: () => {
1388
- inputListener.off();
1389
- compositionStartListener.off();
1390
- compositionEndListener.off();
1391
- },
1392
- };
1393
- }
1394
- /**
1395
- * 双击监听,适配移动端
1396
- * @param $el 监听的元素
1397
- * @param handler 处理的回调函数
1398
- * @param options 监听器的配置
1399
- */
1400
- onDoubleClick(
1401
- $el: DOMUtilsTargetElementType,
1402
- handler: (event: MouseEvent | PointerEvent | TouchEvent, option: DOMUtilsDoubleClickOption) => void | Promise<void>,
1403
- options?: DOMUtilsEventListenerOption | boolean
1404
- ): {
1405
- off(): void;
1406
- };
1407
- /**
1408
- * 双击监听,适配移动端
1409
- * @param $el 监听的元素
1410
- * @param selector 子元素选择器
1411
- * @param handler 处理的回调函数
1412
- * @param options 监听器的配置
1413
- */
1414
- onDoubleClick(
1415
- $el: DOMUtilsTargetElementType,
1416
- selector: string | string[] | undefined | null,
1417
- handler: (event: MouseEvent | PointerEvent | TouchEvent, option: DOMUtilsDoubleClickOption) => void | Promise<void>,
1418
- options?: DOMUtilsEventListenerOption | boolean
1419
- ): {
1420
- off(): void;
1421
- };
1422
- onDoubleClick(...args: any[]): {
1423
- off(): void;
1424
- } {
1425
- const $el: DOMUtilsTargetElementType = args[0];
1426
- let selector: string | string[] | undefined | null = void 0;
1427
- let handler: (
1428
- event: MouseEvent | PointerEvent | TouchEvent,
1429
- option: DOMUtilsDoubleClickOption
1430
- ) => void | Promise<void>;
1431
- let options: DOMUtilsEventListenerOption | boolean | undefined;
1432
- if (args.length === 2) {
1433
- if (typeof args[1] === "function") {
1434
- handler = args[1];
1435
- } else {
1436
- throw new TypeError("handler is not a function");
1437
- }
1438
- } else if (args.length === 3) {
1439
- if (typeof args[1] === "function") {
1440
- handler = args[1];
1441
- options = args[2];
1442
- } else {
1443
- selector = args[1];
1444
- handler = args[2];
1445
- }
1446
- } else if (args.length === 4) {
1447
- selector = args[1];
1448
- handler = args[2];
1449
- options = args[3];
1450
- } else {
1451
- throw new Error("args length error");
1452
- }
1453
-
1454
- let $click: Element | null = null;
1455
- let isDoubleClick = false;
1456
- let timer: number | undefined = void 0;
1457
- /** 是否是移动端点击 */
1458
- let isMobileTouch = false;
1459
- /** 检测是否是单击的延迟时间 */
1460
- const checkClickTime = 200;
1461
-
1462
- const dblclick_handler = async (evt: MouseEvent | PointerEvent | TouchEvent, option: DOMUtilsDoubleClickOption) => {
1463
- if (evt.type === "dblclick" && isMobileTouch) {
1464
- // 禁止在移动端触发dblclick事件
1465
- return;
1466
- }
1467
- await handler(evt, option);
1468
- };
1469
-
1470
- const dblClickListener = this.on(
1471
- $el,
1472
- "dblclick",
1473
- (evt) => {
1474
- this.preventEvent(evt);
1475
- dblclick_handler(evt, {
1476
- isDoubleClick: true,
1477
- });
1478
- },
1479
- options
1480
- );
1481
- const touchEndListener = this.on(
1482
- $el,
1483
- "pointerup",
1484
- selector,
1485
- (evt, $selector) => {
1486
- this.preventEvent(evt);
1487
- if (evt.pointerType === "touch") {
1488
- isMobileTouch = true;
1489
- }
1490
- clearTimeout(timer);
1491
- timer = void 0;
1492
- if (isDoubleClick && $click === $selector) {
1493
- isDoubleClick = false;
1494
- $click = null;
1495
- /* 判定为双击 */
1496
- dblclick_handler(evt, {
1497
- isDoubleClick: true,
1498
- });
1499
- } else {
1500
- timer = setTimeout(() => {
1501
- isDoubleClick = false;
1502
- // 判断为单击
1503
- dblclick_handler(evt, {
1504
- isDoubleClick: false,
1505
- });
1506
- }, checkClickTime);
1507
- isDoubleClick = true;
1508
- $click = $selector;
1509
- }
1510
- },
1511
- options
1512
- );
1513
-
1514
- return {
1515
- off() {
1516
- $click = null;
1517
- dblClickListener.off();
1518
- touchEndListener.off();
1519
- },
1520
- };
1521
- }
1522
- /**
1523
- * 阻止事件传递
1524
- * @param event 要阻止传递的事件
1525
- * @example
1526
- * DOMUtils.preventEvent(event);
1527
- */
1528
- preventEvent(event: Event): boolean;
1529
- /**
1530
- * 通过监听事件来主动阻止事件的传递
1531
- * @param $el 要进行处理的元素
1532
- * @param eventNameList (可选)要阻止的事件名|列表
1533
- * @param capture (可选)是否捕获,默认false
1534
- * @example
1535
- * DOMUtils.preventEvent(document.querySelector("a"),"click")
1536
- */
1537
- preventEvent($el: HTMLElement, eventNameList?: string | string[], capture?: boolean): void;
1538
- preventEvent(...args: any[]) {
1539
- /**
1540
- * 阻止事件的默认行为发生,并阻止事件传播
1541
- */
1542
- const stopEvent = (event: Event) => {
1543
- /* 阻止事件的默认行为发生。例如,当点击一个链接时,浏览器会默认打开链接的URL */
1544
- event?.preventDefault();
1545
- /* 停止事件的传播,阻止它继续向更上层的元素冒泡,事件将不会再传播给其他的元素 */
1546
- event?.stopPropagation();
1547
- /* 阻止事件传播,并且还能阻止元素上的其他事件处理程序被触发 */
1548
- event?.stopImmediatePropagation();
1549
- return false;
1550
- };
1551
- if (args.length === 1) {
1552
- /* 直接阻止事件 */
1553
- return stopEvent(args[0]);
1554
- } else {
1555
- const $el: HTMLElement = args[0];
1556
- let eventNameList: string | string[] = args[1];
1557
- const capture: boolean = args[2];
1558
- /* 添加对应的事件来阻止触发 */
1559
- if (typeof eventNameList === "string") {
1560
- eventNameList = [eventNameList];
1561
- }
1562
- this.on($el, eventNameList, stopEvent, { capture: Boolean(capture) });
1563
- }
1564
- }
1565
- }
1566
-
1567
- const elementEvent = new ElementEvent();
1568
-
1569
- export { elementEvent, ElementEvent };
1
+ import { CommonUtils } from "./CommonUtils";
2
+ import { ElementAnimate } from "./ElementAnimate";
3
+ import { GlobalData } from "./GlobalData";
4
+ import { OriginPrototype } from "./OriginPrototype";
5
+ import type {
6
+ DOMUtils_Event,
7
+ DOMUtils_EventType,
8
+ DOMUtilsAddEventListenerResult,
9
+ DOMUtilsDoubleClickHandler,
10
+ DOMUtilsDoubleClickHandlerWithSelector,
11
+ DOMUtilsDoubleClickOption,
12
+ DOMUtilsElementEventType,
13
+ DOMUtilsEventListenerOption,
14
+ DOMUtilsEventListenerOptionsAttribute,
15
+ } from "./types/DOMUtilsEvent";
16
+ import type { DOMUtilsTargetElementType } from "./types/global";
17
+ import type { WindowApiOption } from "./types/WindowApi";
18
+ import { WindowApi } from "./WindowApi";
19
+
20
+ class ElementEvent extends ElementAnimate {
21
+ windowApi: typeof WindowApi.prototype;
22
+ constructor(windowApiOption?: WindowApiOption) {
23
+ super(windowApiOption);
24
+ this.windowApi = new WindowApi(windowApiOption);
25
+ }
26
+ /** 获取 animationend 在各个浏览器的兼容名 */
27
+ getAnimationEndNameList() {
28
+ return CommonUtils.getAnimationEndNameList();
29
+ }
30
+ /** 获取 transitionend 在各个浏览器的兼容名 */
31
+ getTransitionEndNameList() {
32
+ return CommonUtils.getTransitionEndNameList();
33
+ }
34
+ /**
35
+ * 绑定事件
36
+ * @param element 需要绑定的元素|元素数组|window
37
+ * @param eventType 需要监听的事件
38
+ * @param handler 绑定事件触发的回调函数
39
+ * @param option
40
+ * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
41
+ * + once 表示事件是否只触发一次。默认为false
42
+ * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
43
+ * @example
44
+ * // 监听元素a.xx的click事件
45
+ * DOMUtils.on(document.querySelector("a.xx"),"click",(event)=>{
46
+ * console.log("事件触发",event)
47
+ * })
48
+ * DOMUtils.on("a.xx","click",(event)=>{
49
+ * console.log("事件触发",event)
50
+ * })
51
+ */
52
+ on<T extends DOMUtils_EventType>(
53
+ element: DOMUtilsElementEventType,
54
+ eventType: T | T[],
55
+ handler: <E extends HTMLElement = HTMLElement>(this: E, event: DOMUtils_Event[T]) => void,
56
+ option?: DOMUtilsEventListenerOption | boolean
57
+ ): DOMUtilsAddEventListenerResult;
58
+ /**
59
+ * 绑定事件
60
+ * @param element 需要绑定的元素|元素数组|window
61
+ * @param eventType 需要监听的事件
62
+ * @param handler 绑定事件触发的回调函数
63
+ * @param option
64
+ * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
65
+ * + once 表示事件是否只触发一次。默认为false
66
+ * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
67
+ * @example
68
+ * // 监听元素a.xx的click事件
69
+ * DOMUtils.on(document.querySelector("a.xx"),"click",(event)=>{
70
+ * console.log("事件触发",event)
71
+ * })
72
+ * DOMUtils.on("a.xx","click",(event)=>{
73
+ * console.log("事件触发",event)
74
+ * })
75
+ */
76
+ on<T extends Event>(
77
+ element: DOMUtilsElementEventType,
78
+ eventType: string | string[],
79
+ handler: <E extends HTMLElement = HTMLElement>(this: E, event: T) => void,
80
+ option?: DOMUtilsEventListenerOption | boolean
81
+ ): DOMUtilsAddEventListenerResult;
82
+ /**
83
+ * 绑定事件
84
+ * @param element 需要绑定的元素|元素数组|window
85
+ * @param eventType 需要监听的事件
86
+ * @param selector 子元素选择器
87
+ * @param handler 绑定事件触发的回调函数
88
+ * @param option
89
+ * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
90
+ * + once 表示事件是否只触发一次。默认为false
91
+ * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
92
+ * @example
93
+ * // 监听元素a.xx的click、tap、hover事件
94
+ * DOMUtils.on(document.querySelector("a.xx"),"click tap hover",(event, $selector)=>{
95
+ * console.log("事件触发", event, $selector)
96
+ * })
97
+ * DOMUtils.on("a.xx",["click","tap","hover"],(event, $selector)=>{
98
+ * console.log("事件触发", event, $selector)
99
+ * })
100
+ * @example
101
+ * // 监听全局document下的子元素a.xx的click事件
102
+ * DOMUtils.on(document,"click tap hover","a.xx",(event, $selector)=>{
103
+ * console.log("事件触发", event, $selector)
104
+ * })
105
+ */
106
+ on<T extends DOMUtils_EventType>(
107
+ element: DOMUtilsElementEventType,
108
+ eventType: T | T[],
109
+ selector: string | string[] | undefined | null,
110
+ handler: <E extends HTMLElement = HTMLElement>(this: E, event: DOMUtils_Event[T], $selector: E) => void,
111
+ option?: DOMUtilsEventListenerOption | boolean
112
+ ): DOMUtilsAddEventListenerResult;
113
+ /**
114
+ * 绑定事件
115
+ * @param element 需要绑定的元素|元素数组|window
116
+ * @param eventType 需要监听的事件
117
+ * @param selector 子元素选择器
118
+ * @param handler 绑定事件触发的回调函数
119
+ * @param option
120
+ * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
121
+ * + once 表示事件是否只触发一次。默认为false
122
+ * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
123
+ * @example
124
+ * // 监听元素a.xx的click、tap、hover事件
125
+ * DOMUtils.on(document.querySelector("a.xx"),"click tap hover",(event, $selector)=>{
126
+ * console.log("事件触发", event, $selector)
127
+ * })
128
+ * DOMUtils.on("a.xx",["click","tap","hover"],(event, $selector)=>{
129
+ * console.log("事件触发", event, $selector)
130
+ * })
131
+ * @example
132
+ * // 监听全局document下的子元素a.xx的click事件
133
+ * DOMUtils.on(document,"click tap hover","a.xx",(event, $selector)=>{
134
+ * console.log("事件触发", event, $selector)
135
+ * })
136
+ */
137
+ on<T extends Event>(
138
+ element: DOMUtilsElementEventType,
139
+ eventType: string | string[],
140
+ selector: string | string[] | undefined | null,
141
+ handler: <E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void,
142
+ option?: DOMUtilsEventListenerOption | boolean
143
+ ): DOMUtilsAddEventListenerResult;
144
+ on<T extends Event>(
145
+ element: HTMLElement | string | NodeList | HTMLElement[] | Window | Document | Element | null | typeof globalThis,
146
+ eventType: DOMUtils_EventType | DOMUtils_EventType[] | string | string[],
147
+ selector:
148
+ | string
149
+ | string[]
150
+ | undefined
151
+ | (<E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void)
152
+ | null,
153
+ callback?:
154
+ | (<E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void)
155
+ | DOMUtilsEventListenerOption
156
+ | boolean,
157
+ option?: DOMUtilsEventListenerOption | boolean
158
+ ): DOMUtilsAddEventListenerResult {
159
+ /**
160
+ * 获取option配置
161
+ * @param args
162
+ * @param startIndex
163
+ * @param option
164
+ */
165
+ function getOption(args: IArguments, startIndex: number, option: DOMUtilsEventListenerOption) {
166
+ const currentParam = args[startIndex];
167
+ if (typeof currentParam === "boolean") {
168
+ option.capture = currentParam;
169
+ if (typeof args[startIndex + 1] === "boolean") {
170
+ option.once = args[startIndex + 1];
171
+ }
172
+ if (typeof args[startIndex + 2] === "boolean") {
173
+ option.passive = args[startIndex + 2];
174
+ }
175
+ } else if (
176
+ typeof currentParam === "object" &&
177
+ ("capture" in currentParam ||
178
+ "once" in currentParam ||
179
+ "passive" in currentParam ||
180
+ "isComposedPath" in currentParam)
181
+ ) {
182
+ option.capture = currentParam.capture;
183
+ option.once = currentParam.once;
184
+ option.passive = currentParam.passive;
185
+ option.isComposedPath = currentParam.isComposedPath;
186
+ }
187
+ return option;
188
+ }
189
+
190
+ const that = this;
191
+ // eslint-disable-next-line prefer-rest-params
192
+ const args = arguments;
193
+ if (typeof element === "string") {
194
+ element = that.selectorAll(element);
195
+ }
196
+ if (element == null) {
197
+ return {
198
+ off() {},
199
+ emit() {},
200
+ };
201
+ }
202
+ let $elList: (Element | Document | Window)[] = [];
203
+ if (element instanceof NodeList || Array.isArray(element)) {
204
+ $elList = $elList.concat(Array.from(element as Element[]));
205
+ } else {
206
+ $elList.push(element as Element);
207
+ }
208
+ // 事件名
209
+ let eventTypeList: string[] = [];
210
+ if (Array.isArray(eventType)) {
211
+ eventTypeList = eventTypeList.concat(eventType.filter((it) => typeof it === "string" && it.toString() !== ""));
212
+ } else if (typeof eventType === "string") {
213
+ eventTypeList = eventTypeList.concat(eventType.split(" ").filter((it) => it !== ""));
214
+ }
215
+ // 子元素选择器
216
+ let selectorList: string[] = [];
217
+ if (Array.isArray(selector)) {
218
+ selectorList = selectorList.concat(selector.filter((it) => typeof it === "string" && it.toString() !== ""));
219
+ } else if (typeof selector === "string") {
220
+ selectorList.push(selector);
221
+ }
222
+ // 事件回调
223
+ let listenerCallBack: (this: HTMLElement, event: Event, $selector?: HTMLElement) => void = callback as any;
224
+ // 事件配置
225
+ let listenerOption: DOMUtilsEventListenerOption = {
226
+ capture: false,
227
+ once: false,
228
+ passive: false,
229
+ isComposedPath: false,
230
+ };
231
+ if (typeof selector === "function") {
232
+ // 这是为没有selector的情况
233
+ // 那么它就是callback
234
+ listenerCallBack = selector as any;
235
+ listenerOption = getOption(args, 3, listenerOption);
236
+ } else {
237
+ // 这是存在selector的情况
238
+ listenerOption = getOption(args, 4, listenerOption);
239
+ }
240
+ /**
241
+ * 如果是once,那么删除该监听和元素上的事件和监听
242
+ */
243
+ const checkOptionOnceToRemoveEventListener = () => {
244
+ if (listenerOption.once) {
245
+ that.off(element, eventType as any, selector as any, callback as any, option);
246
+ }
247
+ };
248
+ $elList.forEach((elementItem) => {
249
+ /**
250
+ * 事件回调
251
+ * @param event
252
+ */
253
+ const handlerCallBack = function (event: Event) {
254
+ if (selectorList.length) {
255
+ /* 存在子元素选择器 */
256
+ // 这时候的this和target都是子元素选择器的元素
257
+ let eventTarget = listenerOption.isComposedPath
258
+ ? (event.composedPath()[0] as HTMLElement)
259
+ : (event.target as HTMLElement);
260
+ let totalParent = elementItem;
261
+ if (CommonUtils.isWin(totalParent)) {
262
+ if (totalParent === (that.windowApi.document as any as HTMLElement)) {
263
+ totalParent = that.windowApi.document.documentElement;
264
+ }
265
+ }
266
+ const findValue = selectorList.find((selectorItem) => {
267
+ // 判断目标元素是否匹配选择器
268
+ if (that.matches(eventTarget, selectorItem)) {
269
+ /* 当前目标可以被selector所匹配到 */
270
+ return true;
271
+ }
272
+ /* 在上层与主元素之间寻找可以被selector所匹配到的 */
273
+ const $closestMatches = that.closest<HTMLElement>(eventTarget, selectorItem);
274
+ if ($closestMatches && (<HTMLElement>totalParent)?.contains?.($closestMatches)) {
275
+ eventTarget = $closestMatches;
276
+ return true;
277
+ }
278
+ return false;
279
+ });
280
+ if (findValue) {
281
+ // 这里尝试使用defineProperty修改eventtarget
282
+ try {
283
+ OriginPrototype.Object.defineProperty(event, "target", {
284
+ get() {
285
+ return eventTarget;
286
+ },
287
+ });
288
+ } catch {
289
+ // TODO
290
+ }
291
+ listenerCallBack.call(eventTarget, event as any, eventTarget);
292
+ checkOptionOnceToRemoveEventListener();
293
+ }
294
+ } else {
295
+ // 这时候的this指向监听的元素
296
+ listenerCallBack.call(elementItem as HTMLElement, event as any);
297
+ checkOptionOnceToRemoveEventListener();
298
+ }
299
+ };
300
+
301
+ /* 遍历事件名设置元素事件 */
302
+ eventTypeList.forEach((eventName) => {
303
+ elementItem.addEventListener(eventName, handlerCallBack, listenerOption);
304
+ /* 获取对象上的事件 */
305
+ const elementEvents: {
306
+ [k: string]: DOMUtilsEventListenerOptionsAttribute[];
307
+ } = Reflect.get(elementItem, GlobalData.domEventSymbol) || {};
308
+ /* 初始化对象上的xx事件 */
309
+ elementEvents[eventName] = elementEvents[eventName] || [];
310
+ elementEvents[eventName].push({
311
+ selector: selectorList,
312
+ option: listenerOption,
313
+ handlerCallBack: handlerCallBack,
314
+ callback: listenerCallBack,
315
+ });
316
+ /* 覆盖事件 */
317
+ Reflect.set(elementItem, GlobalData.domEventSymbol, elementEvents);
318
+ });
319
+ });
320
+
321
+ return {
322
+ /**
323
+ * 取消绑定的监听事件
324
+ * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
325
+ */
326
+ off: (
327
+ filter?: (
328
+ value: DOMUtilsEventListenerOptionsAttribute,
329
+ index: number,
330
+ array: DOMUtilsEventListenerOptionsAttribute[]
331
+ ) => boolean
332
+ ) => {
333
+ that.off($elList, eventTypeList, selectorList, listenerCallBack, listenerOption, filter);
334
+ },
335
+ /**
336
+ * 主动触发事件
337
+ * @param extraDetails 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
338
+ * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用callback,但是这种会让使用了$selector的没有值
339
+ */
340
+ emit: (extraDetails?: object, useDispatchToTriggerEvent?: boolean) => {
341
+ that.emit($elList, eventTypeList, extraDetails, useDispatchToTriggerEvent);
342
+ },
343
+ };
344
+ }
345
+ /**
346
+ * 取消绑定事件
347
+ * @param element 需要取消绑定的元素|元素数组
348
+ * @param eventType 需要取消监听的事件
349
+ * @param callback 通过DOMUtils.on绑定的事件函数
350
+ * @param option
351
+ * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
352
+ * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
353
+ * @example
354
+ * // 取消监听元素a.xx所有的click事件
355
+ * DOMUtils.off(document.querySelector("a.xx"),"click")
356
+ * DOMUtils.off("a.xx","click")
357
+ */
358
+ off<T extends DOMUtils_EventType>(
359
+ element: DOMUtilsElementEventType,
360
+ eventType: T | T[],
361
+ callback?: <E extends HTMLElement = HTMLElement>(this: E, event: DOMUtils_Event[T]) => void,
362
+ option?: EventListenerOptions | boolean,
363
+ filter?: (
364
+ value: DOMUtilsEventListenerOptionsAttribute,
365
+ index: number,
366
+ array: DOMUtilsEventListenerOptionsAttribute[]
367
+ ) => boolean
368
+ ): void;
369
+ /**
370
+ * 取消绑定事件
371
+ * @param element 需要取消绑定的元素|元素数组
372
+ * @param eventType 需要取消监听的事件
373
+ * @param callback 通过DOMUtils.on绑定的事件函数
374
+ * @param option
375
+ * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
376
+ * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
377
+ * @example
378
+ * // 取消监听元素a.xxclick事件
379
+ * DOMUtils.off(document.querySelector("a.xx"),"click")
380
+ * DOMUtils.off("a.xx","click")
381
+ */
382
+ off<T extends Event>(
383
+ element: DOMUtilsElementEventType,
384
+ eventType: string | string[],
385
+ callback?: <E extends HTMLElement = HTMLElement>(this: E, event: T) => void,
386
+ option?: EventListenerOptions | boolean,
387
+ filter?: (
388
+ value: DOMUtilsEventListenerOptionsAttribute,
389
+ index: number,
390
+ array: DOMUtilsEventListenerOptionsAttribute[]
391
+ ) => boolean
392
+ ): void;
393
+ /**
394
+ * 取消绑定事件
395
+ * @param element 需要取消绑定的元素|元素数组
396
+ * @param eventType 需要取消监听的事件
397
+ * @param selector 子元素选择器
398
+ * @param callback 通过DOMUtils.on绑定的事件函数
399
+ * @param option
400
+ * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
401
+ * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
402
+ * @example
403
+ * // 取消监听元素a.xxclicktaphover事件
404
+ * DOMUtils.off(document.querySelector("a.xx"),"click tap hover")
405
+ * DOMUtils.off("a.xx",["click","tap","hover"])
406
+ */
407
+ off<T extends DOMUtils_EventType>(
408
+ element: DOMUtilsElementEventType,
409
+ eventType: T | T[],
410
+ selector?: string | string[] | undefined | null,
411
+ callback?: <E extends HTMLElement = HTMLElement>(this: E, event: DOMUtils_Event[T], $selector: E) => void,
412
+ option?: EventListenerOptions | boolean,
413
+ filter?: (
414
+ value: DOMUtilsEventListenerOptionsAttribute,
415
+ index: number,
416
+ array: DOMUtilsEventListenerOptionsAttribute[]
417
+ ) => boolean
418
+ ): void;
419
+ /**
420
+ * 取消绑定事件
421
+ * @param element 需要取消绑定的元素|元素数组
422
+ * @param eventType 需要取消监听的事件
423
+ * @param selector 子元素选择器
424
+ * @param callback 通过DOMUtils.on绑定的事件函数
425
+ * @param option
426
+ * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
427
+ * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
428
+ * @example
429
+ * // 取消监听元素a.xxclicktaphover事件
430
+ * DOMUtils.off(document.querySelector("a.xx"),"click tap hover")
431
+ * DOMUtils.off("a.xx",["click","tap","hover"])
432
+ */
433
+ off<T extends Event>(
434
+ element: DOMUtilsElementEventType,
435
+ eventType: string | string[],
436
+ selector?: string | string[] | undefined | null,
437
+ callback?: <E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void,
438
+ option?: EventListenerOptions | boolean,
439
+ filter?: (
440
+ value: DOMUtilsEventListenerOptionsAttribute,
441
+ index: number,
442
+ array: DOMUtilsEventListenerOptionsAttribute[]
443
+ ) => boolean
444
+ ): void;
445
+ off<T extends Event>(
446
+ element: HTMLElement | string | NodeList | HTMLElement[] | Window | Document | Element | null | typeof globalThis,
447
+ eventType: DOMUtils_EventType | DOMUtils_EventType[] | string | string[],
448
+ selector:
449
+ | string
450
+ | string[]
451
+ | undefined
452
+ | (<E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void)
453
+ | null,
454
+ callback?:
455
+ | (<E extends HTMLElement = HTMLElement>(this: E, event: T, $selector: E) => void)
456
+ | EventListenerOptions
457
+ | boolean,
458
+ option?:
459
+ | EventListenerOptions
460
+ | boolean
461
+ | ((
462
+ value: DOMUtilsEventListenerOptionsAttribute,
463
+ index: number,
464
+ array: DOMUtilsEventListenerOptionsAttribute[]
465
+ ) => boolean),
466
+ filter?: (
467
+ value: DOMUtilsEventListenerOptionsAttribute,
468
+ index: number,
469
+ array: DOMUtilsEventListenerOptionsAttribute[]
470
+ ) => boolean
471
+ ) {
472
+ /**
473
+ * 获取option配置
474
+ * @param args1
475
+ * @param startIndex
476
+ * @param option
477
+ */
478
+ function getOption(args1: IArguments, startIndex: number, option: EventListenerOptions) {
479
+ const currentParam: EventListenerOptions | boolean = args1[startIndex];
480
+ if (typeof currentParam === "boolean") {
481
+ option.capture = currentParam;
482
+ } else if (typeof currentParam === "object" && currentParam != null && "capture" in currentParam) {
483
+ option.capture = currentParam.capture;
484
+ }
485
+ return option;
486
+ }
487
+ const that = this;
488
+ // eslint-disable-next-line prefer-rest-params
489
+ const args = arguments;
490
+ if (typeof element === "string") {
491
+ element = that.selectorAll(element);
492
+ }
493
+ if (element == null) {
494
+ return;
495
+ }
496
+ let $elList: HTMLElement[] = [];
497
+ if (element instanceof NodeList || Array.isArray(element)) {
498
+ element = element as HTMLElement[];
499
+ $elList = $elList.concat(Array.from(element));
500
+ } else {
501
+ $elList.push(element as HTMLElement);
502
+ }
503
+ let eventTypeList: string[] = [];
504
+ if (Array.isArray(eventType)) {
505
+ eventTypeList = eventTypeList.concat(eventType.filter((it) => typeof it === "string" && it.toString() !== ""));
506
+ } else if (typeof eventType === "string") {
507
+ eventTypeList = eventTypeList.concat(eventType.split(" ").filter((it) => it !== ""));
508
+ }
509
+ // 子元素选择器
510
+ let selectorList: string[] = [];
511
+ if (Array.isArray(selector)) {
512
+ selectorList = selectorList.concat(selector.filter((it) => typeof it === "string" && it.toString() !== ""));
513
+ } else if (typeof selector === "string") {
514
+ selectorList.push(selector);
515
+ }
516
+ /**
517
+ * 事件的回调函数
518
+ */
519
+ let listenerCallBack: (this: HTMLElement, event: T, $selector: HTMLElement) => void = callback as any;
520
+
521
+ /**
522
+ * 事件的配置
523
+ */
524
+ let listenerOption: EventListenerOptions = {
525
+ capture: false,
526
+ };
527
+ if (typeof selector === "function") {
528
+ // 这是为没有selector的情况
529
+ // 那么它就是callback
530
+ listenerCallBack = selector;
531
+ listenerOption = getOption(args, 3, listenerOption);
532
+ } else {
533
+ // 这是存在selector的情况
534
+ listenerOption = getOption(args, 4, listenerOption);
535
+ }
536
+ // 是否移除所有事件
537
+ let isRemoveAll = false;
538
+ if (args.length === 2) {
539
+ // 目标函数、事件名
540
+ isRemoveAll = true;
541
+ } else if ((args.length === 3 && typeof args[2] === "string") || Array.isArray(args[2])) {
542
+ // 目标函数、事件名、子元素选择器
543
+ isRemoveAll = true;
544
+ }
545
+ if (args.length === 5 && typeof args[4] === "function" && typeof filter !== "function") {
546
+ // 目标函数、事件名、回调函数、事件配置、过滤函数
547
+ filter = option as (
548
+ value: DOMUtilsEventListenerOptionsAttribute,
549
+ index: number,
550
+ array: DOMUtilsEventListenerOptionsAttribute[]
551
+ ) => boolean;
552
+ }
553
+ $elList.forEach(($elItem) => {
554
+ /* 获取对象上的事件 */
555
+ const elementEvents: {
556
+ [key: string]: DOMUtilsEventListenerOptionsAttribute[];
557
+ } = Reflect.get($elItem, GlobalData.domEventSymbol) || {};
558
+ eventTypeList.forEach((eventName) => {
559
+ const handlers = elementEvents[eventName] || [];
560
+ const filterHandler = typeof filter === "function" ? handlers.filter(filter) : handlers;
561
+ for (let index = 0; index < filterHandler.length; index++) {
562
+ const handler = filterHandler[index];
563
+ let flag = true;
564
+ if (flag && listenerCallBack && handler.callback !== listenerCallBack) {
565
+ // callback不同
566
+ flag = false;
567
+ }
568
+ if (flag && selectorList.length && Array.isArray(handler.selector)) {
569
+ if (JSON.stringify(handler.selector) !== JSON.stringify(selectorList)) {
570
+ // 子元素选择器不同
571
+ flag = false;
572
+ }
573
+ }
574
+ if (
575
+ flag &&
576
+ typeof handler.option.capture === "boolean" &&
577
+ listenerOption.capture !== handler.option.capture
578
+ ) {
579
+ // 事件的配置项不同
580
+ flag = false;
581
+ }
582
+ if (flag || isRemoveAll) {
583
+ $elItem.removeEventListener(eventName, handler.handlerCallBack, handler.option);
584
+ const findIndex = handlers.findIndex((item) => item === handler);
585
+ if (findIndex !== -1) {
586
+ handlers.splice(findIndex, 1);
587
+ }
588
+ }
589
+ }
590
+ if (handlers.length === 0) {
591
+ /* 如果没有任意的handler,那么删除该属性 */
592
+ CommonUtils.delete(elementEvents, eventType);
593
+ }
594
+ });
595
+ Reflect.set($elItem, GlobalData.domEventSymbol, elementEvents);
596
+ });
597
+ }
598
+ /**
599
+ * 取消绑定所有的事件
600
+ * @param element 需要取消绑定的元素|元素数组
601
+ * @param eventType (可选)需要取消监听的事件
602
+ */
603
+ offAll(element: DOMUtilsElementEventType, eventType?: string): void;
604
+ /**
605
+ * 取消绑定所有的事件
606
+ * @param element 需要取消绑定的元素|元素数组
607
+ * @param eventType (可选)需要取消监听的事件
608
+ */
609
+ offAll(element: DOMUtilsElementEventType, eventType?: DOMUtils_EventType | DOMUtils_EventType[]): void;
610
+ /**
611
+ * 取消绑定所有的事件
612
+ * @param element 需要取消绑定的元素|元素数组
613
+ * @param eventType (可选)需要取消监听的事件
614
+ */
615
+ offAll(element: DOMUtilsElementEventType, eventType?: DOMUtils_EventType | DOMUtils_EventType[] | string) {
616
+ const that = this;
617
+ if (typeof element === "string") {
618
+ element = that.selectorAll(element);
619
+ }
620
+ if (element == null) {
621
+ return;
622
+ }
623
+ let $elList: (Element | Document | Window | typeof globalThis | Node | ChildNode | EventTarget)[] = [];
624
+ if (element instanceof NodeList || Array.isArray(element)) {
625
+ $elList = $elList.concat(Array.from(element as HTMLElement[]));
626
+ } else {
627
+ $elList.push(element);
628
+ }
629
+
630
+ let eventTypeList: string[] = [];
631
+ if (Array.isArray(eventType)) {
632
+ eventTypeList = eventTypeList.concat(eventType as string[]);
633
+ } else if (typeof eventType === "string") {
634
+ eventTypeList = eventTypeList.concat(eventType.split(" "));
635
+ }
636
+ $elList.forEach(($elItem) => {
637
+ const symbolList = [...new Set([...Object.getOwnPropertySymbols($elItem), GlobalData.domEventSymbol])];
638
+ symbolList.forEach((symbolItem) => {
639
+ if (!symbolItem.toString().startsWith("Symbol(events_")) {
640
+ return;
641
+ }
642
+ const elementEvents: {
643
+ [key: string]: DOMUtilsEventListenerOptionsAttribute[];
644
+ } = Reflect.get($elItem, symbolItem) || {};
645
+ const iterEventNameList = eventTypeList.length ? eventTypeList : Object.keys(elementEvents);
646
+ iterEventNameList.forEach((eventName) => {
647
+ const handlers: DOMUtilsEventListenerOptionsAttribute[] = elementEvents[eventName];
648
+ if (!handlers) {
649
+ return;
650
+ }
651
+ for (const handler of handlers) {
652
+ $elItem.removeEventListener(eventName, handler.handlerCallBack, {
653
+ capture: handler.option.capture,
654
+ });
655
+ }
656
+ const events = Reflect.get($elItem, symbolItem);
657
+ CommonUtils.delete(events, eventName);
658
+ });
659
+ });
660
+ });
661
+ }
662
+
663
+ /**
664
+ * 等待文档加载完成后执行指定的函数
665
+ * @param callback 需要执行的函数
666
+ * @example
667
+ * DOMUtils.onReady(function(){
668
+ * console.log("文档加载完毕")
669
+ * });
670
+ * > "文档加载完毕"
671
+ * @example
672
+ * await DOMUtils.onReady();
673
+ * console.log("文档加载完毕");
674
+ * > "文档加载完毕"
675
+ */
676
+ onReady(): Promise<void>;
677
+ onReady(callback: (...args: any[]) => any): void;
678
+ onReady(...args: any[]): void | Promise<void> {
679
+ const callback: ((...args: any[]) => any) | undefined = args[0];
680
+ // 异步回调
681
+ let resolve: ((...args: any[]) => any) | undefined = void 0;
682
+ const that = this;
683
+ /**
684
+ * 监听目标
685
+ */
686
+ const listenTargetList = [
687
+ {
688
+ target: that.windowApi.document,
689
+ eventType: "DOMContentLoaded",
690
+ callback: () => {
691
+ ReadyChecker.completed();
692
+ },
693
+ },
694
+ {
695
+ target: that.windowApi.window,
696
+ eventType: "load",
697
+ callback: () => {
698
+ ReadyChecker.completed();
699
+ },
700
+ },
701
+ ];
702
+ const ReadyChecker = {
703
+ init() {
704
+ if (args.length === 0) {
705
+ return new Promise<void>((__resolve__) => {
706
+ resolve = __resolve__;
707
+ ReadyChecker.check();
708
+ });
709
+ } else {
710
+ ReadyChecker.check();
711
+ }
712
+ },
713
+ check() {
714
+ if (ReadyChecker.isReady()) {
715
+ /* 检查document状态 */
716
+ setTimeout(() => {
717
+ ReadyChecker.completed();
718
+ }, 0);
719
+ } else {
720
+ /* 添加监听 */
721
+ ReadyChecker.onCompleted();
722
+ }
723
+ },
724
+ /**
725
+ * 检测文档是否加载完毕
726
+ */
727
+ isReady() {
728
+ try {
729
+ if (
730
+ that.windowApi.document.readyState === "complete" ||
731
+ // @ts-expect-error
732
+ (that.windowApi.document.readyState !== "loading" && !that.windowApi.document.documentElement.doScroll)
733
+ ) {
734
+ return true;
735
+ } else {
736
+ return false;
737
+ }
738
+ } catch {
739
+ return false;
740
+ }
741
+ },
742
+ /**
743
+ * 成功加载完毕后触发的回调函数
744
+ */
745
+ completed() {
746
+ ReadyChecker.offCompleted();
747
+ if (typeof callback === "function") {
748
+ callback();
749
+ }
750
+ if (typeof resolve === "function") {
751
+ resolve();
752
+ }
753
+ },
754
+ /**
755
+ * 添加监听
756
+ */
757
+ onCompleted() {
758
+ for (const item of listenTargetList) {
759
+ that.on(item.target, item.eventType, item.callback);
760
+ }
761
+ },
762
+ /**
763
+ * 移除监听
764
+ */
765
+ offCompleted() {
766
+ for (const item of listenTargetList) {
767
+ that.off(item.target, item.eventType, item.callback);
768
+ }
769
+ },
770
+ };
771
+
772
+ return ReadyChecker.init();
773
+ }
774
+ /**
775
+ * 主动触发事件
776
+ * @param element 需要触发的元素|元素数组|window
777
+ * @param eventType 需要触发的事件
778
+ * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用通过.on监听的callback,但是这种会让使用了$selector的没有值
779
+ * @example
780
+ * // 触发元素a.xxclick事件
781
+ * DOMUtils.emit(document.querySelector("a.xx"),"click")
782
+ * DOMUtils.emit("a.xx","click")
783
+ * // 触发元素a.xxclicktaphover事件
784
+ * DOMUtils.emit(document.querySelector("a.xx"),"click tap hover")
785
+ * DOMUtils.emit("a.xx",["click","tap","hover"])
786
+ */
787
+ emit(
788
+ element: DOMUtilsTargetElementType | Element | DocumentFragment | any[] | typeof globalThis | Window | Document,
789
+ eventType: string | string[],
790
+ useDispatchToTriggerEvent?: boolean
791
+ ): void;
792
+ /**
793
+ * 主动触发事件
794
+ * @param element 需要触发的元素|元素数组|window
795
+ * @param eventType 需要触发的事件
796
+ * @param extraDetails 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
797
+ * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用通过.on监听的callback(),但是这种只有一个入参,如果使用$selector则没有值
798
+ * @example
799
+ * // 触发元素a.xxclick事件
800
+ * DOMUtils.emit(document.querySelector("a.xx"),"click")
801
+ * DOMUtils.emit("a.xx","click")
802
+ * // 触发元素a.xxclicktaphover事件
803
+ * DOMUtils.emit(document.querySelector("a.xx"),"click tap hover")
804
+ * DOMUtils.emit("a.xx",["click","tap","hover"])
805
+ */
806
+ emit(
807
+ element: DOMUtilsTargetElementType | Element | DocumentFragment | any[] | typeof globalThis | Window | Document,
808
+ eventType: string | string[],
809
+ extraDetails?: object,
810
+ useDispatchToTriggerEvent?: boolean
811
+ ): void;
812
+ /**
813
+ * 主动触发事件
814
+ * @param element 需要触发的元素|元素数组|window
815
+ * @param eventType 需要触发的事件
816
+ * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用通过.on监听的callback(),但是这种只有一个入参,如果使用$selector则没有值
817
+ * @example
818
+ * // 触发元素a.xxclick事件
819
+ * DOMUtils.emit(document.querySelector("a.xx"),"click")
820
+ * DOMUtils.emit("a.xx","click")
821
+ * // 触发元素a.xxclicktaphover事件
822
+ * DOMUtils.emit(document.querySelector("a.xx"),"click tap hover")
823
+ * DOMUtils.emit("a.xx",["click","tap","hover"])
824
+ */
825
+ emit(
826
+ element: Element | string | NodeList | any[] | Window | Document,
827
+ eventType: DOMUtils_EventType | DOMUtils_EventType[],
828
+ useDispatchToTriggerEvent?: boolean
829
+ ): void;
830
+ /**
831
+ * 主动触发事件
832
+ * @param element 需要触发的元素|元素数组|window
833
+ * @param eventType 需要触发的事件
834
+ * @param extraDetails 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
835
+ * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用通过.on监听的callback(),但是这种只有一个入参,如果使用$selector则没有值
836
+ * @example
837
+ * // 触发元素a.xxclick事件
838
+ * DOMUtils.emit(document.querySelector("a.xx"),"click")
839
+ * DOMUtils.emit("a.xx","click")
840
+ * // 触发元素a.xxclicktaphover事件
841
+ * DOMUtils.emit(document.querySelector("a.xx"),"click tap hover")
842
+ * DOMUtils.emit("a.xx",["click","tap","hover"])
843
+ */
844
+ emit(
845
+ element: Element | string | NodeList | any[] | Window | Document,
846
+ eventType: DOMUtils_EventType | DOMUtils_EventType[],
847
+ extraDetails?: object,
848
+ useDispatchToTriggerEvent?: boolean
849
+ ): void;
850
+ /**
851
+ * 主动触发事件
852
+ * @param element 需要触发的元素|元素数组|window
853
+ * @param eventType 需要触发的事件
854
+ * @param extraDetails 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
855
+ * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true,如果为false,则直接调用通过.on监听的callback(),但是这种只有一个入参,如果使用$selector则没有值
856
+ * @example
857
+ * // 触发元素a.xxclick事件
858
+ * DOMUtils.emit(document.querySelector("a.xx"),"click")
859
+ * DOMUtils.emit("a.xx","click")
860
+ * // 触发元素a.xxclicktaphover事件
861
+ * DOMUtils.emit(document.querySelector("a.xx"),"click tap hover")
862
+ * DOMUtils.emit("a.xx",["click","tap","hover"])
863
+ */
864
+ emit(
865
+ element: Element | string | NodeList | any[] | Window | Document,
866
+ eventType: DOMUtils_EventType | DOMUtils_EventType[] | string | string[],
867
+ extraDetails?: object | boolean,
868
+ useDispatchToTriggerEvent: boolean = true
869
+ ) {
870
+ const that = this;
871
+ if (typeof element === "string") {
872
+ element = that.selectorAll(element);
873
+ }
874
+ if (element == null) {
875
+ return;
876
+ }
877
+ let $elList: (Document | Window | Element)[] = [];
878
+ if (element instanceof NodeList || Array.isArray(element)) {
879
+ $elList = $elList.concat(Array.from(element));
880
+ } else {
881
+ $elList.push(element);
882
+ }
883
+ let eventTypeList: string[] = [];
884
+ if (Array.isArray(eventType)) {
885
+ eventTypeList = eventType.filter((it) => typeof it === "string" && it.trim() !== "");
886
+ } else if (typeof eventType === "string") {
887
+ eventTypeList = eventType.split(" ");
888
+ }
889
+
890
+ $elList.forEach(($elItem) => {
891
+ /* 获取对象上的事件 */
892
+ const elementEvents: {
893
+ [key: string]: DOMUtilsEventListenerOptionsAttribute[];
894
+ } = Reflect.get($elItem, GlobalData.domEventSymbol) || {};
895
+ eventTypeList.forEach((eventTypeItem) => {
896
+ let event: Event = null as any;
897
+ if (extraDetails && extraDetails instanceof Event) {
898
+ event = extraDetails;
899
+ } else {
900
+ // 构造事件
901
+ event = new Event(eventTypeItem);
902
+ if (typeof extraDetails === "object" && extraDetails != null) {
903
+ const detailKeys = Object.keys(extraDetails);
904
+ detailKeys.forEach((keyName) => {
905
+ const value = Reflect.get(extraDetails, keyName);
906
+ // 在event上添加属性
907
+ Reflect.set(event, keyName, value);
908
+ });
909
+ }
910
+ }
911
+ if (useDispatchToTriggerEvent == false && eventTypeItem in elementEvents) {
912
+ // 直接调用监听的事件
913
+ elementEvents[eventTypeItem].forEach((eventsItem) => {
914
+ eventsItem.handlerCallBack(event);
915
+ });
916
+ } else {
917
+ $elItem.dispatchEvent(event);
918
+ }
919
+ });
920
+ });
921
+ }
922
+
923
+ /**
924
+ * 监听或触发元素的click事件
925
+ * @param element 目标元素
926
+ * @param handler (可选)事件处理函数
927
+ * @param details (可选)赋予触发的Event的额外属性
928
+ * @param useDispatchToEmit (可选)是否使用dispatchEvent来触发事件,默认true
929
+ * @example
930
+ * // 触发元素a.xx的click事件
931
+ * DOMUtils.click(document.querySelector("a.xx"))
932
+ * DOMUtils.click("a.xx")
933
+ * DOMUtils.click("a.xx",function(){
934
+ * console.log("触发click事件成功")
935
+ * })
936
+ * */
937
+ click(
938
+ element: DOMUtilsTargetElementType | Element | DocumentFragment | typeof globalThis | Window,
939
+ handler?: (this: HTMLElement, event: DOMUtils_Event["click"]) => void,
940
+ details?: object,
941
+ useDispatchToEmit?: boolean
942
+ ) {
943
+ const that = this;
944
+ if (typeof element === "string") {
945
+ element = that.selectorAll(element);
946
+ }
947
+ if (element == null) {
948
+ return;
949
+ }
950
+ if (CommonUtils.isNodeList(element)) {
951
+ // 设置
952
+ element.forEach(($ele) => {
953
+ that.click($ele as HTMLElement, handler, details, useDispatchToEmit);
954
+ });
955
+ return;
956
+ }
957
+ if (handler == null) {
958
+ that.emit(element, "click", details, useDispatchToEmit);
959
+ } else {
960
+ that.on(element, "click", null, handler);
961
+ }
962
+ }
963
+ /**
964
+ * 监听或触发元素的blur事件
965
+ * @param element 目标元素
966
+ * @param handler (可选)事件处理函数
967
+ * @param details (可选)赋予触发的Event的额外属性
968
+ * @param useDispatchToEmit (可选)是否使用dispatchEvent来触发事件,默认true
969
+ * @example
970
+ * // 触发元素a.xx的blur事件
971
+ * DOMUtils.blur(document.querySelector("a.xx"))
972
+ * DOMUtils.blur("a.xx")
973
+ * DOMUtils.blur("a.xx",function(){
974
+ * console.log("触发blur事件成功")
975
+ * })
976
+ * */
977
+ blur(
978
+ element: DOMUtilsTargetElementType | Element | DocumentFragment | typeof globalThis | Window,
979
+ handler?: (this: HTMLElement, event: DOMUtils_Event["blur"]) => void,
980
+ details?: object,
981
+ useDispatchToEmit?: boolean
982
+ ) {
983
+ const that = this;
984
+ if (typeof element === "string") {
985
+ element = that.selectorAll(element);
986
+ }
987
+ if (element == null) {
988
+ return;
989
+ }
990
+ if (CommonUtils.isNodeList(element)) {
991
+ // 设置
992
+ element.forEach(($ele) => {
993
+ that.focus($ele as HTMLElement, handler, details, useDispatchToEmit);
994
+ });
995
+ return;
996
+ }
997
+ if (handler === null) {
998
+ that.emit(element, "blur", details, useDispatchToEmit);
999
+ } else {
1000
+ that.on(element, "blur", null, handler as (event: Event) => void);
1001
+ }
1002
+ }
1003
+ /**
1004
+ * 监听或触发元素的focus事件
1005
+ * @param element 目标元素
1006
+ * @param handler (可选)事件处理函数
1007
+ * @param details (可选)赋予触发的Event的额外属性
1008
+ * @param useDispatchToEmit (可选)是否使用dispatchEvent来触发事件,默认true
1009
+ * @example
1010
+ * // 触发元素a.xx的focus事件
1011
+ * DOMUtils.focus(document.querySelector("a.xx"))
1012
+ * DOMUtils.focus("a.xx")
1013
+ * DOMUtils.focus("a.xx",function(){
1014
+ * console.log("触发focus事件成功")
1015
+ * })
1016
+ * */
1017
+ focus(
1018
+ element: DOMUtilsTargetElementType | Element | DocumentFragment | typeof globalThis | Window,
1019
+ handler?: (this: HTMLElement, event: DOMUtils_Event["focus"]) => void,
1020
+ details?: object,
1021
+ useDispatchToEmit?: boolean
1022
+ ) {
1023
+ const that = this;
1024
+ if (typeof element === "string") {
1025
+ element = that.selectorAll(element);
1026
+ }
1027
+ if (element == null) {
1028
+ return;
1029
+ }
1030
+ if (CommonUtils.isNodeList(element)) {
1031
+ // 设置
1032
+ element.forEach(($ele) => {
1033
+ that.focus($ele as HTMLElement, handler, details, useDispatchToEmit);
1034
+ });
1035
+ return;
1036
+ }
1037
+ if (handler == null) {
1038
+ that.emit(element, "focus", details, useDispatchToEmit);
1039
+ } else {
1040
+ that.on(element, "focus", null, handler);
1041
+ }
1042
+ }
1043
+ /**
1044
+ * 当鼠标移入或移出元素时触发事件
1045
+ * @param element 当前元素
1046
+ * @param handler 事件处理函数
1047
+ * @param option 配置
1048
+ * @example
1049
+ * // 监听a.xx元素的移入或移出
1050
+ * DOMUtils.onHover(document.querySelector("a.xx"),()=>{
1051
+ * console.log("移入/移除");
1052
+ * })
1053
+ * DOMUtils.onHover("a.xx",()=>{
1054
+ * console.log("移入/移除");
1055
+ * })
1056
+ */
1057
+ onHover(
1058
+ element: DOMUtilsTargetElementType | Element | DocumentFragment | Node,
1059
+ handler: (this: HTMLElement, event: DOMUtils_Event["hover"]) => void,
1060
+ option?: boolean | DOMUtilsEventListenerOption
1061
+ ) {
1062
+ const that = this;
1063
+ if (typeof element === "string") {
1064
+ element = that.selectorAll(element);
1065
+ }
1066
+ if (element == null) {
1067
+ return;
1068
+ }
1069
+ if (CommonUtils.isNodeList(element)) {
1070
+ // 设置
1071
+ element.forEach(($ele) => {
1072
+ that.onHover($ele as HTMLElement, handler, option);
1073
+ });
1074
+ return;
1075
+ }
1076
+ that.on(element, "mouseenter", null, handler, option);
1077
+ that.on(element, "mouseleave", null, handler, option);
1078
+ }
1079
+ /**
1080
+ * 监听动画结束
1081
+ * @param element 监听的元素
1082
+ * @param handler 触发的回调函数
1083
+ * @param option 配置项,这里默认配置once为true
1084
+ */
1085
+ onAnimationend(
1086
+ element: HTMLElement | string | Element | DocumentFragment,
1087
+ handler: (this: HTMLElement, event: DOMUtils_Event["animationend"]) => void,
1088
+ option?: boolean | DOMUtilsEventListenerOption
1089
+ ) {
1090
+ const that = this;
1091
+ if (typeof element === "string") {
1092
+ element = that.selector(element)!;
1093
+ }
1094
+ if (element == null) {
1095
+ return;
1096
+ }
1097
+ const defaultOption: DOMUtilsEventListenerOption = {
1098
+ once: true,
1099
+ };
1100
+ Object.assign(defaultOption, option || {});
1101
+ const eventNameList = CommonUtils.getAnimationEndNameList();
1102
+ that.on(element, eventNameList, null, handler, defaultOption);
1103
+ if (!defaultOption.once) {
1104
+ return {
1105
+ off() {
1106
+ that.off(element, eventNameList, null, handler, defaultOption);
1107
+ },
1108
+ };
1109
+ }
1110
+ }
1111
+ /**
1112
+ * 监听过渡结束
1113
+ * @param element 监听的元素
1114
+ * @param handler 触发的回调函数
1115
+ * @param option 配置项,这里默认配置once为true
1116
+ */
1117
+ onTransitionend(
1118
+ element: HTMLElement | string | Element | DocumentFragment,
1119
+ handler: (this: HTMLElement, event: DOMUtils_Event["transitionend"]) => void,
1120
+ option?: boolean | DOMUtilsEventListenerOption
1121
+ ) {
1122
+ const that = this;
1123
+ if (typeof element === "string") {
1124
+ element = that.selector(element)!;
1125
+ }
1126
+ if (element == null) {
1127
+ return;
1128
+ }
1129
+ const defaultOption: DOMUtilsEventListenerOption = {
1130
+ once: true,
1131
+ };
1132
+ Object.assign(defaultOption, option || {});
1133
+ const eventNameList = CommonUtils.getTransitionEndNameList();
1134
+ that.on(element, eventNameList, null, handler, defaultOption);
1135
+ if (!defaultOption.once) {
1136
+ return {
1137
+ off() {
1138
+ that.off(element, eventNameList, null, handler, defaultOption);
1139
+ },
1140
+ };
1141
+ }
1142
+ }
1143
+ /**
1144
+ * 当按键松开时触发事件
1145
+ * keydown - > keypress - > keyup
1146
+ * @param element 当前元素
1147
+ * @param handler 事件处理函数
1148
+ * @param option 配置
1149
+ * @example
1150
+ * // 监听a.xx元素的按键松开
1151
+ * DOMUtils.keyup(document.querySelector("a.xx"),()=>{
1152
+ * console.log("按键松开");
1153
+ * })
1154
+ * DOMUtils.keyup("a.xx",()=>{
1155
+ * console.log("按键松开");
1156
+ * })
1157
+ */
1158
+ onKeyup(
1159
+ element: DOMUtilsTargetElementType | Element | DocumentFragment | Window | Node | typeof globalThis,
1160
+ handler: (this: HTMLElement, event: DOMUtils_Event["keyup"]) => void,
1161
+ option?: boolean | DOMUtilsEventListenerOption
1162
+ ) {
1163
+ const that = this;
1164
+ if (element == null) {
1165
+ return;
1166
+ }
1167
+ if (typeof element === "string") {
1168
+ element = that.selectorAll(element);
1169
+ }
1170
+ if (CommonUtils.isNodeList(element)) {
1171
+ // 设置
1172
+ element.forEach(($ele) => {
1173
+ that.onKeyup($ele as HTMLElement, handler, option);
1174
+ });
1175
+ return;
1176
+ }
1177
+ that.on(element, "keyup", null, handler, option);
1178
+ }
1179
+ /**
1180
+ * 当按键按下时触发事件
1181
+ * keydown - > keypress - > keyup
1182
+ * @param element 目标
1183
+ * @param handler 事件处理函数
1184
+ * @param option 配置
1185
+ * @example
1186
+ * // 监听a.xx元素的按键按下
1187
+ * DOMUtils.keydown(document.querySelector("a.xx"),()=>{
1188
+ * console.log("按键按下");
1189
+ * })
1190
+ * DOMUtils.keydown("a.xx",()=>{
1191
+ * console.log("按键按下");
1192
+ * })
1193
+ */
1194
+ onKeydown(
1195
+ element: DOMUtilsTargetElementType | Element | DocumentFragment | Window | Node | typeof globalThis,
1196
+ handler: (this: HTMLElement, event: DOMUtils_Event["keydown"]) => void,
1197
+ option?: boolean | DOMUtilsEventListenerOption
1198
+ ) {
1199
+ const that = this;
1200
+ if (element == null) {
1201
+ return;
1202
+ }
1203
+ if (typeof element === "string") {
1204
+ element = that.selectorAll(element);
1205
+ }
1206
+ if (CommonUtils.isNodeList(element)) {
1207
+ // 设置
1208
+ element.forEach(($ele) => {
1209
+ that.onKeydown($ele as HTMLElement, handler, option);
1210
+ });
1211
+ return;
1212
+ }
1213
+ that.on(element, "keydown", null, handler, option);
1214
+ }
1215
+ /**
1216
+ * 当按键按下时触发事件
1217
+ * keydown - > keypress - > keyup
1218
+ * @param element 目标
1219
+ * @param handler 事件处理函数
1220
+ * @param option 配置
1221
+ * @example
1222
+ * // 监听a.xx元素的按键按下
1223
+ * DOMUtils.keypress(document.querySelector("a.xx"),()=>{
1224
+ * console.log("按键按下");
1225
+ * })
1226
+ * DOMUtils.keypress("a.xx",()=>{
1227
+ * console.log("按键按下");
1228
+ * })
1229
+ */
1230
+ onKeypress(
1231
+ element: DOMUtilsTargetElementType | Element | DocumentFragment | Window | Node | typeof globalThis,
1232
+ handler: (this: HTMLElement, event: DOMUtils_Event["keypress"]) => void,
1233
+ option?: boolean | DOMUtilsEventListenerOption
1234
+ ) {
1235
+ const that = this;
1236
+ if (element == null) {
1237
+ return;
1238
+ }
1239
+ if (typeof element === "string") {
1240
+ element = that.selectorAll(element);
1241
+ }
1242
+ if (CommonUtils.isNodeList(element)) {
1243
+ // 设置
1244
+ element.forEach(($ele) => {
1245
+ that.onKeypress($ele as HTMLElement, handler, option);
1246
+ });
1247
+ return;
1248
+ }
1249
+ that.on(element, "keypress", null, handler, option);
1250
+ }
1251
+ /**
1252
+ * 监听某个元素键盘按键事件或window全局按键事件
1253
+ * 按下有值的键时触发,按下Ctrl\Alt\Shift\Meta是无值键。按下先触发keydown事件,再触发keypress事件。
1254
+ * @param element 需要监听的对象,可以是全局Window或者某个元素
1255
+ * @param eventName 事件名,默认keypress,keydown - > keypress - > keyup
1256
+ * @param handler 自己定义的回调事件,参数1为当前的key,参数2为组合按键,数组类型,包含ctrl、shift、alt和meta(win键或mac的cmd键)
1257
+ * @param options 监听事件的配置
1258
+ * @example
1259
+ Utils.onKeyboard(window,(keyName,keyValue,otherKey,event)=>{
1260
+ if(keyName === "Enter"){
1261
+ console.log("回车按键的值是:"+keyValue)
1262
+ }
1263
+ if(otherKey.indexOf("ctrl") && keyName === "Enter" ){
1264
+ console.log("Ctrl和回车键");
1265
+ }
1266
+ })
1267
+ * @example
1268
+ 字母和数字键的键码值(keyCode)
1269
+ 按键 键码 按键 键码 按键 键码 按键 键码
1270
+ A 65 J 74 S 83 1 49
1271
+ B 66 K 75 T 84 2 50
1272
+ C 67 L 76 U 85 3 51
1273
+ D 68 M 77 V 86 4 52
1274
+ E 69 N 78 W 87 5 53
1275
+ F 70 O 79 X 88 6 54
1276
+ G 71 P 80 Y 89 7 55
1277
+ H 72 Q 81 Z 90 8 56
1278
+ I 73 R 82 0 48 9 57
1279
+
1280
+ 数字键盘上的键的键码值(keyCode)
1281
+ 功能键键码值(keyCode)
1282
+ 按键 键码 按键 键码 按键 键码 按键 键码
1283
+ 0 96 8 104 F1 112 F7 118
1284
+ 1 97 9 105 F2 113 F8 119
1285
+ 2 98 * 106 F3 114 F9 120
1286
+ 3 99 + 107 F4 115 F10 121
1287
+ 4 100 Enter 108 F5 116 F11 122
1288
+ 5 101 - 109 F6 117 F12 123
1289
+ 6 102 . 110
1290
+ 7 103 / 111
1291
+
1292
+ 控制键键码值(keyCode)
1293
+ 按键 键码 按键 键码 按键 键码 按键 键码
1294
+ BackSpace 8 Esc 27 39 -_ 189
1295
+ Tab 9 Spacebar 32 40 .> 190
1296
+ Clear 12 Page Up 33 Insert 45 /? 191
1297
+ Enter 13 Page Down 34 Delete 46 `~ 192
1298
+ Shift 16 End 35 Num Lock 144 [{ 219
1299
+ Control 17 Home 36 ;: 186 \| 220
1300
+ Alt 18 ← 37 =+ 187 ]} 221
1301
+ Cape Lock 20 ↑ 38 ,< 188 '" 222
1302
+
1303
+ 多媒体键码值(keyCode)
1304
+ 按键 键码
1305
+ 音量加 175
1306
+ 音量减 174
1307
+ 停止 179
1308
+ 静音 173
1309
+ 浏览器 172
1310
+ 邮件 180
1311
+ 搜索 170
1312
+ 收藏 171
1313
+ **/
1314
+ onKeyboard(
1315
+ element: DOMUtilsTargetElementType | Element | DocumentFragment | Window | Node | typeof globalThis,
1316
+ eventName: "keydown" | "keypress" | "keyup" = "keypress",
1317
+ handler: (keyName: string, keyValue: number, otherCodeList: string[], event: KeyboardEvent) => void,
1318
+ options?: DOMUtilsEventListenerOption | boolean
1319
+ ): {
1320
+ removeListen(): void;
1321
+ } {
1322
+ const that = this;
1323
+ if (typeof element === "string") {
1324
+ element = that.selectorAll(element);
1325
+ }
1326
+ const keyboardEventCallBack = function (event: KeyboardEvent) {
1327
+ /** 键名 */
1328
+ const keyName = event.key || event.code;
1329
+ /** 键值 */
1330
+ const keyValue = event.charCode || event.keyCode || event.which;
1331
+ /** 组合键列表 */
1332
+ const otherCodeList: string[] = [];
1333
+ if (event.ctrlKey) {
1334
+ otherCodeList.push("ctrl");
1335
+ }
1336
+ if (event.altKey) {
1337
+ otherCodeList.push("alt");
1338
+ }
1339
+ if (event.metaKey) {
1340
+ otherCodeList.push("meta");
1341
+ }
1342
+ if (event.shiftKey) {
1343
+ otherCodeList.push("shift");
1344
+ }
1345
+ if (typeof handler === "function") {
1346
+ handler(keyName, keyValue, otherCodeList, event);
1347
+ }
1348
+ };
1349
+ that.on(element, eventName, keyboardEventCallBack, options);
1350
+ return {
1351
+ removeListen: () => {
1352
+ that.off(element, eventName, keyboardEventCallBack, options);
1353
+ },
1354
+ };
1355
+ }
1356
+ /**
1357
+ * 监input、textarea的输入框值改变的事件(当输入法输入时,不会触发该监听)
1358
+ * @param $el 输入框元素
1359
+ * @param handler 回调函数
1360
+ * @param option 配置
1361
+ */
1362
+ onInput(
1363
+ $el: HTMLInputElement | HTMLTextAreaElement,
1364
+ handler: (evt: InputEvent) => void | Promise<void>,
1365
+ option?: DOMUtilsEventListenerOption | boolean
1366
+ ) {
1367
+ /**
1368
+ * 是否正在输入中
1369
+ */
1370
+ let isComposite = false;
1371
+ const __callback = async (event: InputEvent) => {
1372
+ if (isComposite) return;
1373
+ await handler(event);
1374
+ };
1375
+ const __composition_start_callback = () => {
1376
+ isComposite = true;
1377
+ };
1378
+ const __composition_end_callback = () => {
1379
+ isComposite = false;
1380
+ this.emit($el, "input", {
1381
+ isComposite,
1382
+ });
1383
+ };
1384
+ const inputListener = this.on($el, "input", __callback, option);
1385
+ const compositionStartListener = this.on($el, "compositionstart", __composition_start_callback, option);
1386
+ const compositionEndListener = this.on($el, "compositionend", __composition_end_callback, option);
1387
+
1388
+ return {
1389
+ off: () => {
1390
+ inputListener.off();
1391
+ compositionStartListener.off();
1392
+ compositionEndListener.off();
1393
+ },
1394
+ };
1395
+ }
1396
+ /**
1397
+ * 双击监听,适配移动端
1398
+ * @param $el 监听的元素
1399
+ * @param handler 处理的回调函数
1400
+ * @param options 监听器的配置
1401
+ */
1402
+ onDoubleClick(
1403
+ $el: DOMUtilsElementEventType,
1404
+ handler: (event: MouseEvent | PointerEvent | TouchEvent, option: DOMUtilsDoubleClickOption) => void | Promise<void>,
1405
+ options?: DOMUtilsEventListenerOption | boolean
1406
+ ): {
1407
+ off(): void;
1408
+ };
1409
+ /**
1410
+ * 双击监听,适配移动端
1411
+ * @param $el 监听的元素
1412
+ * @param selector 子元素选择器
1413
+ * @param handler 处理的回调函数
1414
+ * @param options 监听器的配置
1415
+ */
1416
+ onDoubleClick<T = HTMLElement>(
1417
+ $el: DOMUtilsElementEventType,
1418
+ selector: string | string[],
1419
+ handler: (
1420
+ event: MouseEvent | PointerEvent | TouchEvent,
1421
+ $selector: T,
1422
+ option: DOMUtilsDoubleClickOption
1423
+ ) => void | Promise<void>,
1424
+ options?: DOMUtilsEventListenerOption | boolean
1425
+ ): {
1426
+ off(): void;
1427
+ };
1428
+ onDoubleClick(...args: any[]): {
1429
+ off(): void;
1430
+ } {
1431
+ const $el: DOMUtilsElementEventType = args[0];
1432
+ let selector: string | string[] | undefined | null = void 0;
1433
+ let handler: DOMUtilsDoubleClickHandler | DOMUtilsDoubleClickHandlerWithSelector;
1434
+ let options: DOMUtilsEventListenerOption | boolean | undefined;
1435
+ if (args.length === 2) {
1436
+ if (typeof args[1] === "function") {
1437
+ handler = args[1];
1438
+ } else {
1439
+ throw new TypeError("handler is not a function");
1440
+ }
1441
+ } else if (args.length === 3) {
1442
+ if (typeof args[1] === "function") {
1443
+ handler = args[1];
1444
+ options = args[2];
1445
+ } else {
1446
+ selector = args[1];
1447
+ handler = args[2];
1448
+ }
1449
+ } else if (args.length === 4) {
1450
+ selector = args[1];
1451
+ handler = args[2];
1452
+ options = args[3];
1453
+ } else {
1454
+ throw new Error("args length error");
1455
+ }
1456
+
1457
+ let $click: Element | null = null;
1458
+ let isDoubleClick = false;
1459
+ let timer: number | undefined = void 0;
1460
+ /** 是否是移动端点击 */
1461
+ let isMobileTouch = false;
1462
+ /** 检测是否是单击的延迟时间 */
1463
+ const checkClickTime = 200;
1464
+
1465
+ const dblclick_handler = async (
1466
+ evt: MouseEvent | PointerEvent | TouchEvent,
1467
+ option: DOMUtilsDoubleClickOption,
1468
+ $selector?: HTMLElement
1469
+ ) => {
1470
+ if (evt.type === "dblclick" && isMobileTouch) {
1471
+ // 禁止在移动端触发dblclick事件
1472
+ return;
1473
+ }
1474
+ if ($selector) {
1475
+ await (<DOMUtilsDoubleClickHandlerWithSelector>handler)(evt, $selector, option);
1476
+ } else {
1477
+ await (<DOMUtilsDoubleClickHandler>handler)(evt, option);
1478
+ }
1479
+ };
1480
+
1481
+ const dblClickListener = this.on(
1482
+ $el,
1483
+ "dblclick",
1484
+ selector,
1485
+ (evt, $selector) => {
1486
+ this.preventEvent(evt);
1487
+ dblclick_handler(
1488
+ evt,
1489
+ {
1490
+ isDoubleClick: true,
1491
+ },
1492
+ $selector
1493
+ );
1494
+ },
1495
+ options
1496
+ );
1497
+ const pointerUpListener = this.on(
1498
+ $el,
1499
+ "pointerup",
1500
+ selector,
1501
+ (evt, $selector) => {
1502
+ this.preventEvent(evt);
1503
+ if (evt.pointerType === "touch") {
1504
+ isMobileTouch = true;
1505
+ }
1506
+ clearTimeout(timer);
1507
+ timer = void 0;
1508
+ if (isDoubleClick && $click === $selector) {
1509
+ isDoubleClick = false;
1510
+ $click = null;
1511
+ /* 判定为双击 */
1512
+ dblclick_handler(
1513
+ evt,
1514
+ {
1515
+ isDoubleClick: true,
1516
+ },
1517
+ $selector
1518
+ );
1519
+ } else {
1520
+ timer = setTimeout(() => {
1521
+ isDoubleClick = false;
1522
+ // 判断为单击
1523
+ dblclick_handler(
1524
+ evt,
1525
+ {
1526
+ isDoubleClick: false,
1527
+ },
1528
+ $selector
1529
+ );
1530
+ }, checkClickTime);
1531
+ isDoubleClick = true;
1532
+ $click = $selector;
1533
+ }
1534
+ },
1535
+ options
1536
+ );
1537
+
1538
+ return {
1539
+ off() {
1540
+ $click = null;
1541
+ dblClickListener.off();
1542
+ pointerUpListener.off();
1543
+ },
1544
+ };
1545
+ }
1546
+ /**
1547
+ * 阻止事件传递
1548
+ * @param event 要阻止传递的事件
1549
+ * @example
1550
+ * DOMUtils.preventEvent(event);
1551
+ */
1552
+ preventEvent(event: Event): boolean;
1553
+ /**
1554
+ * 通过监听事件来主动阻止事件的传递
1555
+ * @param $el 要进行处理的元素
1556
+ * @param eventNameList (可选)要阻止的事件名|列表
1557
+ * @param capture (可选)是否捕获,默认false
1558
+ * @example
1559
+ * DOMUtils.preventEvent(document.querySelector("a"),"click")
1560
+ */
1561
+ preventEvent($el: HTMLElement, eventNameList?: string | string[], capture?: boolean): void;
1562
+ preventEvent(...args: any[]) {
1563
+ /**
1564
+ * 阻止事件的默认行为发生,并阻止事件传播
1565
+ */
1566
+ const stopEvent = (event: Event) => {
1567
+ /* 阻止事件的默认行为发生。例如,当点击一个链接时,浏览器会默认打开链接的URL */
1568
+ event?.preventDefault();
1569
+ /* 停止事件的传播,阻止它继续向更上层的元素冒泡,事件将不会再传播给其他的元素 */
1570
+ event?.stopPropagation();
1571
+ /* 阻止事件传播,并且还能阻止元素上的其他事件处理程序被触发 */
1572
+ event?.stopImmediatePropagation();
1573
+ return false;
1574
+ };
1575
+ if (args.length === 1) {
1576
+ /* 直接阻止事件 */
1577
+ return stopEvent(args[0]);
1578
+ } else {
1579
+ const $el: HTMLElement = args[0];
1580
+ let eventNameList: string | string[] = args[1];
1581
+ const capture: boolean = args[2];
1582
+ /* 添加对应的事件来阻止触发 */
1583
+ if (typeof eventNameList === "string") {
1584
+ eventNameList = [eventNameList];
1585
+ }
1586
+ this.on($el, eventNameList, stopEvent, { capture: Boolean(capture) });
1587
+ }
1588
+ }
1589
+ }
1590
+
1591
+ const elementEvent = new ElementEvent();
1592
+
1593
+ export { elementEvent, ElementEvent };