@whitesev/domutils 1.0.0

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.
@@ -0,0 +1,2504 @@
1
+ import { CommonDOMUtils } from "./CommonDOMUtils";
2
+ import { DOMUtilsData } from "./Data";
3
+ import { OriginPrototype } from "./OriginPrototype";
4
+
5
+ class DOMUtils {
6
+ /** 版本号 */
7
+ version = "2024.5.24";
8
+ /**
9
+ * 获取元素的属性值
10
+ * @param element 目标元素
11
+ * @param attrName 属性名
12
+ * @example
13
+ * // 获取a.xx元素的href属性
14
+ * DOMUtils.attr(document.querySelector("a.xx"),"href");
15
+ * DOMUtils.attr("a.xx","href");
16
+ * > https://xxxx....
17
+ */
18
+ attr(element: HTMLElement | string, attrName: string): string;
19
+ /**
20
+ * 设置元素的属性值
21
+ * @param element 目标元素
22
+ * @param attrName 属性名
23
+ * @param attrValue 属性值
24
+ * @example
25
+ * // 修改a.xx元素的href属性为abcd
26
+ * DOMUtils.attr(document.querySelector("a.xx"),"href","abcd");
27
+ * DOMUtils.attr("a.xx","href","abcd");
28
+ */
29
+ attr(
30
+ element: HTMLElement | string,
31
+ attrName: string,
32
+ attrValue: string
33
+ ): void;
34
+ attr(element: HTMLElement | string, attrName: string, attrValue?: string) {
35
+ if (typeof element === "string") {
36
+ element = document.querySelector(element) as HTMLElement;
37
+ }
38
+ if (element == null) {
39
+ return;
40
+ }
41
+ if (attrValue == null) {
42
+ return element.getAttribute(attrName);
43
+ } else {
44
+ element.setAttribute(attrName, attrValue);
45
+ }
46
+ }
47
+ /**
48
+ * 创建元素
49
+ * @param tagName 标签名
50
+ * @param property 属性
51
+ * @param attributes 元素上的自定义属性
52
+ * @example
53
+ * // 创建一个DIV元素,且属性class为xxx
54
+ * DOMUtils.createElement("div",undefined,{ class:"xxx" });
55
+ * > <div class="xxx"></div>
56
+ * @example
57
+ * // 创建一个DIV元素
58
+ * DOMUtils.createElement("div");
59
+ * > <div></div>
60
+ * @example
61
+ * // 创建一个DIV元素
62
+ * DOMUtils.createElement("div","测试");
63
+ * > <div>测试</div>
64
+ */
65
+ createElement<K extends keyof HTMLElementTagNameMap>(
66
+ /** 元素名 */
67
+ tagName: K,
68
+ /** 属性 */
69
+ property?:
70
+ | ({
71
+ [P in keyof HTMLElementTagNameMap[K]]?: HTMLElementTagNameMap[K][P];
72
+ } & {
73
+ [key: string]: any;
74
+ })
75
+ | string,
76
+ /** 自定义属性 */
77
+ attributes?: DOMUtilsCreateElementAttributesMap
78
+ ): HTMLElementTagNameMap[K] {
79
+ let tempElement = document.createElement(tagName);
80
+ if (typeof property === "string") {
81
+ tempElement.innerHTML = property;
82
+ return tempElement;
83
+ }
84
+ if (property == null) {
85
+ property = {};
86
+ }
87
+ if (attributes == null) {
88
+ attributes = {};
89
+ }
90
+ Object.keys(property).forEach((key) => {
91
+ let value = property[key];
92
+ (tempElement as any)[key] = value;
93
+ });
94
+ Object.keys(attributes).forEach((key) => {
95
+ let value = attributes[key];
96
+ if (typeof value === "object") {
97
+ /* object转字符串 */
98
+ value = JSON.stringify(value);
99
+ } else if (typeof value === "function") {
100
+ /* function转字符串 */
101
+ value = value.toString();
102
+ }
103
+ tempElement.setAttribute(key, value);
104
+ });
105
+ return tempElement;
106
+ }
107
+
108
+ /**
109
+ * 获取元素的样式属性值
110
+ * @param element 目标元素
111
+ * @param property 样式属性名或包含多个属性名和属性值的对象
112
+ * @example
113
+ * // 获取元素a.xx的CSS属性display
114
+ * DOMUtils.css(document.querySelector("a.xx"),"display");
115
+ * DOMUtils.css("a.xx","display");
116
+ * > "none"
117
+ * */
118
+ css(
119
+ element: HTMLElement | string,
120
+ property: keyof CSSStyleDeclaration & string
121
+ ): string;
122
+ /**
123
+ * 设置元素的样式属性
124
+ * @param element 目标元素
125
+ * @param property 样式属性名或包含多个属性名和属性值的对象
126
+ * @param value 样式属性值
127
+ * @example
128
+ * // 设置元素a.xx的CSS属性display为block
129
+ * DOMUtils.css(document.querySelector("a.xx"),"display","block");
130
+ * DOMUtils.css(document.querySelector("a.xx"),"display","block !important");
131
+ * DOMUtils.css("a.xx","display","block");
132
+ * DOMUtils.css("a.xx","display","block !important");
133
+ * @example
134
+ * // 设置元素a.xx的CSS属性top为10px
135
+ * DOMUtils.css(document.querySelector("a.xx"),"top","10px");
136
+ * DOMUtils.css(document.querySelector("a.xx"),"top",10);
137
+ * */
138
+ css(
139
+ element: HTMLElement | string,
140
+ property: keyof CSSStyleDeclaration & string,
141
+ value: string | number
142
+ ): string;
143
+ /**
144
+ * 设置元素的样式属性
145
+ * @param element 目标元素
146
+ * @param property 样式属性名或包含多个属性名和属性值的对象
147
+ * @param value 样式属性值
148
+ * @example
149
+ * // 设置元素a.xx的CSS属性display为block
150
+ * DOMUtils.css(document.querySelector("a.xx"),{ display: "block" }});
151
+ * DOMUtils.css(document.querySelector("a.xx"),{ display: "block !important" }});
152
+ * @example
153
+ * // 设置元素a.xx的CSS属性top为10px
154
+ * DOMUtils.css(document.querySelector("a.xx"),{ top: "10px" });
155
+ * DOMUtils.css(document.querySelector("a.xx"),{ top: 10 });
156
+ * */
157
+ css(
158
+ element: HTMLElement | string,
159
+ property: {
160
+ [P in keyof CSSStyleDeclaration]?: CSSStyleDeclaration[P];
161
+ }
162
+ ): string;
163
+ css(
164
+ element: HTMLElement | string,
165
+ property:
166
+ | keyof CSSStyleDeclaration
167
+ | string
168
+ | {
169
+ [P in keyof CSSStyleDeclaration]?:
170
+ | string
171
+ | number
172
+ | CSSStyleDeclaration[P];
173
+ },
174
+ value?: string | number
175
+ ) {
176
+ /**
177
+ * 把纯数字没有px的加上
178
+ */
179
+ function handlePixe(propertyName: string, propertyValue: string | number) {
180
+ let allowAddPixe = [
181
+ "width",
182
+ "height",
183
+ "top",
184
+ "left",
185
+ "right",
186
+ "bottom",
187
+ "font-size",
188
+ ];
189
+ if (typeof propertyValue === "number") {
190
+ propertyValue = propertyValue.toString();
191
+ }
192
+ if (
193
+ typeof propertyValue === "string" &&
194
+ allowAddPixe.includes(propertyName) &&
195
+ propertyValue.match(/[0-9]$/gi)
196
+ ) {
197
+ propertyValue = propertyValue + "px";
198
+ }
199
+ return propertyValue;
200
+ }
201
+ if (typeof element === "string") {
202
+ element = document.querySelector(element) as HTMLElement;
203
+ }
204
+ if (element == null) {
205
+ return;
206
+ }
207
+ if (typeof property === "string") {
208
+ if (value == null) {
209
+ return getComputedStyle(element).getPropertyValue(property);
210
+ } else {
211
+ if (value === "string" && value.includes("!important")) {
212
+ element.style.setProperty(property, value, "important");
213
+ } else {
214
+ value = handlePixe(property, value);
215
+ element.style.setProperty(property, value);
216
+ }
217
+ }
218
+ } else if (typeof property === "object") {
219
+ for (let prop in property) {
220
+ if (
221
+ typeof property[prop] === "string" &&
222
+ (property[prop] as string).includes("!important")
223
+ ) {
224
+ element.style.setProperty(
225
+ prop,
226
+ property[prop] as string,
227
+ "important"
228
+ );
229
+ } else {
230
+ property[prop] = handlePixe(prop, property[prop] as string);
231
+ element.style.setProperty(prop, property[prop] as string);
232
+ }
233
+ }
234
+ }
235
+ }
236
+ /**
237
+ * 获取元素的文本内容
238
+ * @param element 目标元素
239
+ * @param text (可选)文本内容
240
+ * @returns 如果传入了text,则返回undefined;否则返回文本内容
241
+ * @example
242
+ * // 设置元素a.xx的文本内容为abcd
243
+ * DOMUtils.text(document.querySelector("a.xx"),"abcd")
244
+ * DOMUtils.text("a.xx","abcd")
245
+ * DOMUtils.text("a.xx",document.querySelector("b"))
246
+ * */
247
+ text(element: HTMLElement | string): string;
248
+ /**
249
+ * 设置元素的文本内容
250
+ * @param element 目标元素
251
+ * @param text (可选)文本内容
252
+ * @returns 如果传入了text,则返回undefined;否则返回文本内容
253
+ * @example
254
+ * // 设置元素a.xx的文本内容为abcd
255
+ * DOMUtils.text(document.querySelector("a.xx"),"abcd")
256
+ * DOMUtils.text("a.xx","abcd")
257
+ * DOMUtils.text("a.xx",document.querySelector("b"))
258
+ * */
259
+ text(
260
+ element: HTMLElement | string,
261
+ text: string | HTMLElement | Element
262
+ ): void;
263
+ text(element: HTMLElement | string, text?: string | HTMLElement | Element) {
264
+ if (typeof element === "string") {
265
+ element = document.querySelector(element) as HTMLElement;
266
+ }
267
+ if (element == null) {
268
+ return;
269
+ }
270
+ if (text == null) {
271
+ return element.textContent || element.innerText;
272
+ } else {
273
+ if (text instanceof Node) {
274
+ text = text.textContent || (text as HTMLElement).innerText;
275
+ }
276
+ if ("textContent" in element) {
277
+ element.textContent = text as string;
278
+ } else if ("innerText" in element) {
279
+ (element as HTMLElement).innerText = text as string;
280
+ }
281
+ }
282
+ }
283
+
284
+ /**
285
+ * 设置元素的HTML内容
286
+ * @param element 目标元素
287
+ * @param html (可选)HTML内容|元素
288
+ * @returns 如果传入了html,则返回undefined;否则返回HTML内容
289
+ * @example
290
+ * // 设置元素a.xx的文本内容为<b>abcd</b>
291
+ * DOMUtils.html(document.querySelector("a.xx"),"<b>abcd</b>")
292
+ * DOMUtils.html("a.xx","<b>abcd</b>")
293
+ * DOMUtils.html("a.xx",document.querySelector("b"))
294
+ * */
295
+ html(
296
+ element: HTMLElement | string,
297
+ html: string | HTMLElement | Element
298
+ ): void;
299
+ /**
300
+ * 获取元素的HTML内容
301
+ * @param element 目标元素
302
+ * @param html (可选)HTML内容|元素
303
+ * @returns 如果传入了html,则返回undefined;否则返回HTML内容
304
+ * @example
305
+ * // 设置元素a.xx的文本内容为<b>abcd</b>
306
+ * DOMUtils.html(document.querySelector("a.xx"),"<b>abcd</b>")
307
+ * DOMUtils.html("a.xx","<b>abcd</b>")
308
+ * DOMUtils.html("a.xx",document.querySelector("b"))
309
+ * */
310
+ html(element: HTMLElement | string): string;
311
+ html(element: HTMLElement | string, html?: string | HTMLElement | Element) {
312
+ if (typeof element === "string") {
313
+ element = document.querySelector(element) as HTMLElement;
314
+ }
315
+ if (element == null) {
316
+ return;
317
+ }
318
+ if (html == null) {
319
+ return element.innerHTML;
320
+ } else {
321
+ if (html instanceof Node) {
322
+ html = html.innerHTML;
323
+ }
324
+ if ("innerHTML" in element) {
325
+ element.innerHTML = html;
326
+ }
327
+ }
328
+ }
329
+
330
+ /**
331
+ * 绑定或触发元素的click事件
332
+ * @param element 目标元素
333
+ * @param handler (可选)事件处理函数
334
+ * @param details (可选)赋予触发的Event的额外属性
335
+ * @param useDispatchToTriggerEvent (可选)是否使用dispatchEvent来触发事件,默认true
336
+ * @example
337
+ * // 触发元素a.xx的click事件
338
+ * DOMUtils.click(document.querySelector("a.xx"))
339
+ * DOMUtils.click("a.xx")
340
+ * DOMUtils.click("a.xx",function(){
341
+ * console.log("触发click事件成功")
342
+ * })
343
+ * */
344
+ click(
345
+ element: HTMLElement | string | Window,
346
+ handler?: (event: PointerEvent | MouseEvent) => void,
347
+ details?: object,
348
+ useDispatchToTriggerEvent?: boolean
349
+ ) {
350
+ let DOMUtilsContext = this;
351
+ if (typeof element === "string") {
352
+ element = document.querySelector(element) as HTMLElement;
353
+ }
354
+ if (element == null) {
355
+ return;
356
+ }
357
+ if (handler == null) {
358
+ DOMUtilsContext.trigger(
359
+ element,
360
+ "click",
361
+ details,
362
+ useDispatchToTriggerEvent
363
+ );
364
+ } else {
365
+ DOMUtilsContext.on(element, "click", null, handler);
366
+ }
367
+ }
368
+ /**
369
+ * 绑定或触发元素的blur事件
370
+ * @param element 目标元素
371
+ * @param handler (可选)事件处理函数
372
+ * @param details (可选)赋予触发的Event的额外属性
373
+ * @param useDispatchToTriggerEvent (可选)是否使用dispatchEvent来触发事件,默认true
374
+ * @example
375
+ * // 触发元素a.xx的blur事件
376
+ * DOMUtils.blur(document.querySelector("a.xx"))
377
+ * DOMUtils.blur("a.xx")
378
+ * DOMUtils.blur("a.xx",function(){
379
+ * console.log("触发blur事件成功")
380
+ * })
381
+ * */
382
+ blur(
383
+ element: HTMLElement | string | Window,
384
+ handler?: (event: Event) => void,
385
+ details?: object,
386
+ useDispatchToTriggerEvent?: boolean
387
+ ) {
388
+ let DOMUtilsContext = this;
389
+ if (typeof element === "string") {
390
+ element = document.querySelector(element) as HTMLElement;
391
+ }
392
+ if (element == null) {
393
+ return;
394
+ }
395
+ if (handler === null) {
396
+ DOMUtilsContext.trigger(
397
+ element,
398
+ "blur",
399
+ details,
400
+ useDispatchToTriggerEvent
401
+ );
402
+ } else {
403
+ DOMUtilsContext.on(
404
+ element,
405
+ "blur",
406
+ null,
407
+ handler as (event: Event) => void
408
+ );
409
+ }
410
+ }
411
+ /**
412
+ * 绑定或触发元素的focus事件
413
+ * @param element 目标元素
414
+ * @param handler (可选)事件处理函数
415
+ * @param details (可选)赋予触发的Event的额外属性
416
+ * @param useDispatchToTriggerEvent (可选)是否使用dispatchEvent来触发事件,默认true
417
+ * @example
418
+ * // 触发元素a.xx的focus事件
419
+ * DOMUtils.focus(document.querySelector("a.xx"))
420
+ * DOMUtils.focus("a.xx")
421
+ * DOMUtils.focus("a.xx",function(){
422
+ * console.log("触发focus事件成功")
423
+ * })
424
+ * */
425
+ focus(
426
+ element: HTMLElement | string | Window,
427
+ handler?: (event: Event) => void,
428
+ details?: object,
429
+ useDispatchToTriggerEvent?: boolean
430
+ ) {
431
+ let DOMUtilsContext = this;
432
+ if (typeof element === "string") {
433
+ element = document.querySelector(element) as HTMLElement;
434
+ }
435
+ if (element == null) {
436
+ return;
437
+ }
438
+ if (handler == null) {
439
+ DOMUtilsContext.trigger(
440
+ element,
441
+ "focus",
442
+ details,
443
+ useDispatchToTriggerEvent
444
+ );
445
+ } else {
446
+ DOMUtilsContext.on(element, "focus", null, handler);
447
+ }
448
+ }
449
+ /**
450
+ * 获取移动元素的transform偏移
451
+ */
452
+ getTransform(
453
+ element: HTMLElement,
454
+ isShow: boolean = false
455
+ ): {
456
+ transformLeft: number;
457
+ transformTop: number;
458
+ } {
459
+ let DOMUtilsContext = this;
460
+ let transform_left = 0;
461
+ let transform_top = 0;
462
+ if (!(isShow || (!isShow && CommonDOMUtils.isShow(element)))) {
463
+ /* 未显示 */
464
+ let { recovery } = CommonDOMUtils.showElement(element);
465
+ let transformInfo = DOMUtilsContext.getTransform(element, true);
466
+ recovery();
467
+ return transformInfo;
468
+ }
469
+ let elementTransform = getComputedStyle(element).transform;
470
+ if (
471
+ elementTransform != null &&
472
+ elementTransform !== "none" &&
473
+ elementTransform !== ""
474
+ ) {
475
+ let elementTransformSplit = elementTransform
476
+ .match(/\((.+)\)/)?.[1]
477
+ .split(",");
478
+ if (elementTransformSplit) {
479
+ transform_left = Math.abs(parseInt(elementTransformSplit[4]));
480
+ transform_top = Math.abs(parseInt(elementTransformSplit[5]));
481
+ } else {
482
+ transform_left = 0;
483
+ transform_top = 0;
484
+ }
485
+ }
486
+ return {
487
+ transformLeft: transform_left,
488
+ transformTop: transform_top,
489
+ };
490
+ }
491
+
492
+ /**
493
+ * 设置元素的value属性值
494
+ * @param element 目标元素
495
+ * @param value (可选)value属性值
496
+ * @returns 如果传入了value,则返回undefined;否则返回value属性值
497
+ * > true
498
+ * @example
499
+ * // 修改元素input.xx的复选框值为true
500
+ * DOMUtils.val(document.querySelector("input.xx"),true)
501
+ * DOMUtils.val("input.xx",true)
502
+ * */
503
+ val(element: HTMLInputElement | string, value: string | boolean): void;
504
+ /**
505
+ * 获取value属性值
506
+ * @param element 目标元素
507
+ * @example
508
+ * // 获取元素textarea的值
509
+ * DOMUtils.val(document.querySelector("textarea.xx"))
510
+ * */
511
+ val(element: HTMLInputElement | string): string;
512
+ /**
513
+ * 获取value属性值
514
+ * @param element 目标元素
515
+ * @example
516
+ * // 获取元素input.xx的复选框值
517
+ * DOMUtils.val(document.querySelector("input.xx"))
518
+ * DOMUtils.val("input.xx")
519
+ * */
520
+ val(element: HTMLInputElement): boolean | string;
521
+ val(element: HTMLInputElement | string, value?: string | boolean) {
522
+ if (typeof element === "string") {
523
+ element = document.querySelector(element) as HTMLInputElement;
524
+ }
525
+ if (element == null) {
526
+ return;
527
+ }
528
+ if (value == null) {
529
+ if (
530
+ element.localName === "input" &&
531
+ (element.type === "checkbox" || element.type === "radio")
532
+ ) {
533
+ return element.checked;
534
+ } else {
535
+ return element.value;
536
+ }
537
+ } else {
538
+ if (
539
+ element.localName === "input" &&
540
+ (element.type === "checkbox" || element.type === "radio")
541
+ ) {
542
+ element.checked = !!value;
543
+ } else {
544
+ element.value = value as string;
545
+ }
546
+ }
547
+ }
548
+
549
+ /**
550
+ * 获取元素的属性值
551
+ * @param element 目标元素
552
+ * @param propName 属性名
553
+ * @param propValue 属性值
554
+ * @example
555
+ * // 获取元素a.xx的属性data-value
556
+ * DOMUtils.val(document.querySelector("a.xx"),"data-value")
557
+ * DOMUtils.val("a.xx","data-value")
558
+ * > undefined
559
+ * */
560
+ prop<T extends any>(element: HTMLElement | string, propName: string): T;
561
+ /**
562
+ * 设置元素的属性值
563
+ * @param element 目标元素
564
+ * @param propName 属性名
565
+ * @param propValue 属性值
566
+ * @example
567
+ * // 设置元素a.xx的属性data-value为1
568
+ * DOMUtils.val(document.querySelector("a.xx"),"data-value",1)
569
+ * DOMUtils.val("a.xx","data-value",1)
570
+ * */
571
+ prop<T extends any>(
572
+ element: HTMLElement | string,
573
+ propName: string,
574
+ propValue: T
575
+ ): void;
576
+ prop(element: HTMLElement | string, propName: string, propValue?: any) {
577
+ if (element == null) {
578
+ return;
579
+ }
580
+ if (typeof element === "string") {
581
+ element = document.querySelector(element) as HTMLElement;
582
+ }
583
+ if (propValue == null) {
584
+ return (element as any)[propName];
585
+ } else {
586
+ (element as any)[propName] = propValue;
587
+ }
588
+ }
589
+ /**
590
+ * 移除元素的属性
591
+ * @param element 目标元素
592
+ * @param attrName 属性名
593
+ * @example
594
+ * // 移除元素a.xx的属性data-value
595
+ * DOMUtils.removeAttr(document.querySelector("a.xx"),"data-value")
596
+ * DOMUtils.removeAttr("a.xx","data-value")
597
+ * */
598
+ removeAttr(element: HTMLElement | string, attrName: string) {
599
+ if (typeof element === "string") {
600
+ element = document.querySelector(element) as HTMLElement;
601
+ }
602
+ if (element == null) {
603
+ return;
604
+ }
605
+ element.removeAttribute(attrName);
606
+ }
607
+ /**
608
+ * 移除元素class名
609
+ * @param element 目标元素
610
+ * @param className 类名
611
+ * @example
612
+ * // 移除元素a.xx的className为xx
613
+ * DOMUtils.removeClass(document.querySelector("a.xx"),"xx")
614
+ * DOMUtils.removeClass("a.xx","xx")
615
+ */
616
+ removeClass(element: HTMLElement | string, className: string) {
617
+ if (typeof element === "string") {
618
+ element = document.querySelector(element) as HTMLElement;
619
+ }
620
+ if (element == null) {
621
+ return;
622
+ }
623
+ if (className == null) {
624
+ return;
625
+ }
626
+ element.classList.remove(className);
627
+ }
628
+ /**
629
+ * 移除元素的属性
630
+ * @param element 目标元素
631
+ * @param propName 属性名
632
+ * @example
633
+ * // 移除元素a.xx的href属性
634
+ * DOMUtils.removeProp(document.querySelector("a.xx"),"href")
635
+ * DOMUtils.removeProp("a.xx","href")
636
+ * */
637
+ removeProp(element: HTMLElement | string, propName: string) {
638
+ if (typeof element === "string") {
639
+ element = document.querySelector(element) as HTMLElement;
640
+ }
641
+ if (element == null) {
642
+ return;
643
+ }
644
+ CommonDOMUtils.delete(element, propName);
645
+ }
646
+ /**
647
+ * 将一个元素替换为另一个元素
648
+ * @param element 目标元素
649
+ * @param newElement 新元素
650
+ * @example
651
+ * // 替换元素a.xx为b.xx
652
+ * DOMUtils.replaceWith(document.querySelector("a.xx"),document.querySelector("b.xx"))
653
+ * DOMUtils.replaceWith("a.xx",'<b class="xx"></b>')
654
+ */
655
+ replaceWith(
656
+ element: HTMLElement | string | NodeList | HTMLElement[] | Node,
657
+ newElement: HTMLElement | string | Node
658
+ ) {
659
+ let DOMUtilsContext = this;
660
+ if (typeof element === "string") {
661
+ element = document.querySelector(element) as HTMLElement;
662
+ }
663
+ if (element == null) {
664
+ return;
665
+ }
666
+ if (typeof newElement === "string") {
667
+ newElement = DOMUtilsContext.parseHTML(newElement, false, false);
668
+ }
669
+ if (element instanceof NodeList || element instanceof Array) {
670
+ element.forEach((item) => {
671
+ DOMUtilsContext.replaceWith(item, newElement);
672
+ });
673
+ } else {
674
+ element!.parentElement!.replaceChild(newElement as Node, element);
675
+ }
676
+ }
677
+ /**
678
+ * 给元素添加class
679
+ * @param element 目标元素
680
+ * @param className class名
681
+ * @example
682
+ * // 元素a.xx的className添加_vue_
683
+ * DOMUtils.addClass(document.querySelector("a.xx"),"_vue_")
684
+ * DOMUtils.addClass("a.xx","_vue_")
685
+ * */
686
+ addClass(element: HTMLElement | string, className: string) {
687
+ if (typeof element === "string") {
688
+ element = document.querySelector(element) as HTMLElement;
689
+ }
690
+ if (element == null) {
691
+ return;
692
+ }
693
+ element.classList.add(className);
694
+ }
695
+ /**
696
+ * 函数在元素内部末尾添加子元素或HTML字符串
697
+ * @param element 目标元素
698
+ * @param content 子元素或HTML字符串
699
+ * @example
700
+ * // 元素a.xx的内部末尾添加一个元素
701
+ * DOMUtils.append(document.querySelector("a.xx"),document.querySelector("b.xx"))
702
+ * DOMUtils.append("a.xx","'<b class="xx"></b>")
703
+ * */
704
+ append(element: HTMLElement | string, content: HTMLElement | string) {
705
+ if (typeof element === "string") {
706
+ element = document.querySelector(element) as HTMLElement;
707
+ }
708
+ if (element == null) {
709
+ return;
710
+ }
711
+ if (typeof content === "string") {
712
+ element.insertAdjacentHTML("beforeend", content);
713
+ } else {
714
+ element.appendChild(content);
715
+ }
716
+ }
717
+ /**
718
+ * 函数 在元素内部开头添加子元素或HTML字符串
719
+ * @param element 目标元素
720
+ * @param content 子元素或HTML字符串
721
+ * @example
722
+ * // 元素a.xx内部开头添加一个元素
723
+ * DOMUtils.prepend(document.querySelector("a.xx"),document.querySelector("b.xx"))
724
+ * DOMUtils.prepend("a.xx","'<b class="xx"></b>")
725
+ * */
726
+ prepend(element: HTMLElement | string, content: HTMLElement | string) {
727
+ if (typeof element === "string") {
728
+ element = document.querySelector(element) as HTMLElement;
729
+ }
730
+ if (element == null) {
731
+ return;
732
+ }
733
+ if (typeof content === "string") {
734
+ element.insertAdjacentHTML("afterbegin", content);
735
+ } else {
736
+ element.insertBefore(content, element.firstChild);
737
+ }
738
+ }
739
+ /**
740
+ * 在元素后面添加兄弟元素或HTML字符串
741
+ * @param element 目标元素
742
+ * @param content 兄弟元素或HTML字符串
743
+ * @example
744
+ * // 元素a.xx后面添加一个元素
745
+ * DOMUtils.after(document.querySelector("a.xx"),document.querySelector("b.xx"))
746
+ * DOMUtils.after("a.xx","'<b class="xx"></b>")
747
+ * */
748
+ after(element: HTMLElement | string, content: HTMLElement | string) {
749
+ if (typeof element === "string") {
750
+ element = document.querySelector(element) as HTMLElement;
751
+ }
752
+ if (element == null) {
753
+ return;
754
+ }
755
+ if (typeof content === "string") {
756
+ element.insertAdjacentHTML("afterend", content);
757
+ } else {
758
+ element!.parentElement!.insertBefore(content, element.nextSibling);
759
+ }
760
+ }
761
+ /**
762
+ * 在元素前面添加兄弟元素或HTML字符串
763
+ * @param element 目标元素
764
+ * @param content 兄弟元素或HTML字符串
765
+ * @example
766
+ * // 元素a.xx前面添加一个元素
767
+ * DOMUtils.before(document.querySelector("a.xx"),document.querySelector("b.xx"))
768
+ * DOMUtils.before("a.xx","'<b class="xx"></b>")
769
+ * */
770
+ before(element: HTMLElement | string, content: HTMLElement | string) {
771
+ if (typeof element === "string") {
772
+ element = document.querySelector(element) as HTMLElement;
773
+ }
774
+ if (element == null) {
775
+ return;
776
+ }
777
+ if (typeof content === "string") {
778
+ element.insertAdjacentHTML("beforebegin", content);
779
+ } else {
780
+ element!.parentElement!.insertBefore(content, element);
781
+ }
782
+ }
783
+ /**
784
+ * 移除元素
785
+ * @param target 目标元素
786
+ * @example
787
+ * // 元素a.xx前面添加一个元素
788
+ * DOMUtils.remove(document.querySelector("a.xx"))
789
+ * DOMUtils.remove(document.querySelectorAll("a.xx"))
790
+ * DOMUtils.remove("a.xx")
791
+ * */
792
+ remove(target: HTMLElement | string | NodeList | HTMLElement[]) {
793
+ let DOMUtilsContext = this;
794
+ if (typeof target === "string") {
795
+ target = document.querySelectorAll(target) as NodeListOf<HTMLElement>;
796
+ }
797
+ if (target == null) {
798
+ return;
799
+ }
800
+ if (target instanceof NodeList || target instanceof Array) {
801
+ target = target as HTMLElement[];
802
+ for (const element of target) {
803
+ DOMUtilsContext.remove(element);
804
+ }
805
+ } else {
806
+ target.remove();
807
+ }
808
+ }
809
+ /**
810
+ * 移除元素的所有子元素
811
+ * @param element 目标元素
812
+ * @example
813
+ * // 移除元素a.xx元素的所有子元素
814
+ * DOMUtils.empty(document.querySelector("a.xx"))
815
+ * DOMUtils.empty("a.xx")
816
+ * */
817
+ empty(element: HTMLElement | string) {
818
+ if (typeof element === "string") {
819
+ element = document.querySelector(element) as HTMLElement;
820
+ }
821
+ if (element == null) {
822
+ return;
823
+ }
824
+ element.innerHTML = "";
825
+ }
826
+ /**
827
+ * 绑定事件
828
+ * @param element 需要绑定的元素|元素数组|window
829
+ * @param eventType 需要监听的事件
830
+ * @param callback 绑定事件触发的回调函数
831
+ * @param option
832
+ * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
833
+ * + once 表示事件是否只触发一次。默认为false
834
+ * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
835
+ * @example
836
+ * // 监听元素a.xx的click事件
837
+ * DOMUtils.on(document.querySelector("a.xx"),"click",(event)=>{
838
+ * console.log("事件触发",event)
839
+ * })
840
+ * DOMUtils.on("a.xx","click",(event)=>{
841
+ * console.log("事件触发",event)
842
+ * })
843
+ */
844
+ on<T extends Event>(
845
+ element:
846
+ | HTMLElement
847
+ | string
848
+ | NodeList
849
+ | HTMLElement[]
850
+ | Window
851
+ | Document
852
+ | Element
853
+ | null
854
+ | typeof globalThis,
855
+ eventType: DOMUtils_EventType | DOMUtils_EventType[],
856
+ callback: (event: T) => void,
857
+ option?: boolean | AddEventListenerOptions
858
+ ): void;
859
+ /**
860
+ * 绑定事件
861
+ * @param element 需要绑定的元素|元素数组|window
862
+ * @param eventType 需要监听的事件
863
+ * @param callback 绑定事件触发的回调函数
864
+ * @param option
865
+ * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
866
+ * + once 表示事件是否只触发一次。默认为false
867
+ * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
868
+ * @example
869
+ * // 监听元素a.xx的click事件
870
+ * DOMUtils.on(document.querySelector("a.xx"),"click",(event)=>{
871
+ * console.log("事件触发",event)
872
+ * })
873
+ * DOMUtils.on("a.xx","click",(event)=>{
874
+ * console.log("事件触发",event)
875
+ * })
876
+ */
877
+ on<T extends Event>(
878
+ element:
879
+ | HTMLElement
880
+ | string
881
+ | NodeList
882
+ | HTMLElement[]
883
+ | Window
884
+ | Document
885
+ | Element
886
+ | null
887
+ | typeof globalThis,
888
+ eventType: string,
889
+ callback: (event: T) => void,
890
+ option?: boolean | AddEventListenerOptions
891
+ ): void;
892
+ /**
893
+ * 绑定事件
894
+ * @param element 需要绑定的元素|元素数组|window
895
+ * @param eventType 需要监听的事件
896
+ * @param selector 子元素选择器
897
+ * @param callback 绑定事件触发的回调函数
898
+ * @param option
899
+ * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
900
+ * + once 表示事件是否只触发一次。默认为false
901
+ * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
902
+ * @example
903
+ * // 监听元素a.xx的click、tap、hover事件
904
+ * DOMUtils.on(document.querySelector("a.xx"),"click tap hover",(event)=>{
905
+ * console.log("事件触发",event)
906
+ * })
907
+ * DOMUtils.on("a.xx",["click","tap","hover"],(event)=>{
908
+ * console.log("事件触发",event)
909
+ * })
910
+ * @example
911
+ * // 监听全局document下的子元素a.xx的click事件
912
+ * DOMUtils.on(document,"click tap hover","a.xx",(event)=>{
913
+ * console.log("事件触发",event)
914
+ * })
915
+ */
916
+ on<T extends Event>(
917
+ element:
918
+ | HTMLElement
919
+ | string
920
+ | NodeList
921
+ | HTMLElement[]
922
+ | Window
923
+ | Document
924
+ | Element
925
+ | null
926
+ | typeof globalThis,
927
+ eventType: DOMUtils_EventType | DOMUtils_EventType[],
928
+ selector: string | undefined | null,
929
+ callback: (event: T) => void,
930
+ option?: boolean | AddEventListenerOptions
931
+ ): void;
932
+ /**
933
+ * 绑定事件
934
+ * @param element 需要绑定的元素|元素数组|window
935
+ * @param eventType 需要监听的事件
936
+ * @param selector 子元素选择器
937
+ * @param callback 绑定事件触发的回调函数
938
+ * @param option
939
+ * + capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
940
+ * + once 表示事件是否只触发一次。默认为false
941
+ * + passive 表示事件监听器是否不会调用preventDefault()。默认为false
942
+ * @example
943
+ * // 监听元素a.xx的click、tap、hover事件
944
+ * DOMUtils.on(document.querySelector("a.xx"),"click tap hover",(event)=>{
945
+ * console.log("事件触发",event)
946
+ * })
947
+ * DOMUtils.on("a.xx",["click","tap","hover"],(event)=>{
948
+ * console.log("事件触发",event)
949
+ * })
950
+ * @example
951
+ * // 监听全局document下的子元素a.xx的click事件
952
+ * DOMUtils.on(document,"click tap hover","a.xx",(event)=>{
953
+ * console.log("事件触发",event)
954
+ * })
955
+ */
956
+ on<T extends Event>(
957
+ element:
958
+ | HTMLElement
959
+ | string
960
+ | NodeList
961
+ | HTMLElement[]
962
+ | Window
963
+ | Document
964
+ | Element
965
+ | null
966
+ | typeof globalThis,
967
+ eventType: string,
968
+ selector: string | undefined | null,
969
+ callback: (event: T) => void,
970
+ option?: boolean | AddEventListenerOptions
971
+ ): void;
972
+ on<T extends Event>(
973
+ element:
974
+ | HTMLElement
975
+ | string
976
+ | NodeList
977
+ | HTMLElement[]
978
+ | Window
979
+ | Document
980
+ | Element
981
+ | null
982
+ | typeof globalThis,
983
+ eventType: DOMUtils_EventType | DOMUtils_EventType[] | string,
984
+ selector: string | undefined | ((event: T) => void) | null,
985
+ callback?: ((event: T) => void) | boolean | AddEventListenerOptions,
986
+ option?: boolean | AddEventListenerOptions
987
+ ) {
988
+ /**
989
+ * 获取option配置
990
+ * @param args
991
+ * @param startIndex
992
+ * @param option
993
+ */
994
+ function getOption(
995
+ args: IArguments,
996
+ startIndex: number,
997
+ option: AddEventListenerOptions
998
+ ) {
999
+ if (typeof args[startIndex] === "boolean") {
1000
+ option.capture = args[startIndex];
1001
+ if (typeof args[startIndex + 1] === "boolean") {
1002
+ option.once = args[startIndex + 1];
1003
+ }
1004
+ if (typeof args[startIndex + 2] === "boolean") {
1005
+ option.passive = args[startIndex + 2];
1006
+ }
1007
+ } else if (
1008
+ typeof args[startIndex] === "object" &&
1009
+ ("capture" in args[startIndex] ||
1010
+ "once" in args[startIndex] ||
1011
+ "passive" in args[startIndex])
1012
+ ) {
1013
+ option.capture = args[startIndex].capture;
1014
+ option.once = args[startIndex].once;
1015
+ option.passive = args[startIndex].passive;
1016
+ }
1017
+ return option;
1018
+ }
1019
+
1020
+ let DOMUtilsContext = this;
1021
+ let args = arguments;
1022
+ if (typeof element === "string") {
1023
+ element = document.querySelectorAll(element);
1024
+ }
1025
+ if (element == null) {
1026
+ return;
1027
+ }
1028
+ let elementList: HTMLElement[] = [];
1029
+ if (element instanceof NodeList || Array.isArray(element)) {
1030
+ element = element as HTMLElement[];
1031
+ elementList = [...element];
1032
+ } else {
1033
+ elementList.push(element as HTMLElement);
1034
+ }
1035
+
1036
+ let eventTypeList: string[] = [];
1037
+ if (Array.isArray(eventType)) {
1038
+ eventTypeList = eventTypeList.concat(eventType as string[]);
1039
+ } else if (typeof eventType === "string") {
1040
+ eventTypeList = eventTypeList.concat(eventType.split(" "));
1041
+ }
1042
+ let _selector_: string | undefined = selector as any;
1043
+ let _callback_: (event: T) => void = callback as any;
1044
+ let _option_: AddEventListenerOptions = {
1045
+ capture: false,
1046
+ once: false,
1047
+ passive: false,
1048
+ };
1049
+ if (typeof selector === "function") {
1050
+ /* 这是为没有selector的情况 */
1051
+ _selector_ = void 0;
1052
+ _callback_ = selector;
1053
+ _option_ = getOption(args, 3, _option_);
1054
+ } else {
1055
+ /* 这是存在selector的情况 */
1056
+ _option_ = getOption(args, 4, _option_);
1057
+ }
1058
+ /**
1059
+ * 如果是once,那么删除该监听和元素上的事件和监听
1060
+ */
1061
+ function checkOptionOnceToRemoveEventListener() {
1062
+ if (_option_.once) {
1063
+ DOMUtilsContext.off(
1064
+ element,
1065
+ eventType as any,
1066
+ selector as any,
1067
+ callback as any,
1068
+ option
1069
+ );
1070
+ }
1071
+ }
1072
+ elementList.forEach((elementItem) => {
1073
+ function ownCallBack(event: Event) {
1074
+ let target = event.target as HTMLElement;
1075
+ if (_selector_) {
1076
+ /* 存在自定义子元素选择器 */
1077
+ let totalParent = CommonDOMUtils.isWin(elementItem)
1078
+ ? document.documentElement
1079
+ : elementItem;
1080
+ if (target.matches(_selector_)) {
1081
+ /* 当前目标可以被selector所匹配到 */
1082
+ _callback_.call(target, event as any);
1083
+ checkOptionOnceToRemoveEventListener();
1084
+ } else if (
1085
+ target.closest(_selector_) &&
1086
+ totalParent.contains(target.closest(_selector_))
1087
+ ) {
1088
+ /* 在上层与主元素之间寻找可以被selector所匹配到的 */
1089
+ let closestElement = target.closest(_selector_);
1090
+ /* event的target值不能直接修改 */
1091
+ OriginPrototype.Object.defineProperty(event, "target", {
1092
+ get() {
1093
+ return closestElement;
1094
+ },
1095
+ });
1096
+ _callback_.call(closestElement, event as any);
1097
+ checkOptionOnceToRemoveEventListener();
1098
+ }
1099
+ } else {
1100
+ _callback_.call(elementItem, event as any);
1101
+ checkOptionOnceToRemoveEventListener();
1102
+ }
1103
+ }
1104
+
1105
+ /* 遍历事件名设置元素事件 */
1106
+ eventTypeList.forEach((eventName) => {
1107
+ elementItem.addEventListener(eventName, ownCallBack, _option_);
1108
+
1109
+ if (_callback_ && (_callback_ as any).delegate) {
1110
+ elementItem.setAttribute("data-delegate", _selector_ as string);
1111
+ }
1112
+ /* 获取对象上的事件 */
1113
+ let elementEvents =
1114
+ (elementItem as any)[DOMUtilsData.SymbolEvents] || {};
1115
+ /* 初始化对象上的xx事件 */
1116
+ elementEvents[eventName] = elementEvents[eventName] || [];
1117
+ elementEvents[eventName].push({
1118
+ selector: _selector_,
1119
+ option: _option_,
1120
+ callback: ownCallBack,
1121
+ originCallBack: _callback_,
1122
+ });
1123
+ /* 覆盖事件 */
1124
+ (elementItem as any)[DOMUtilsData.SymbolEvents] = elementEvents;
1125
+ });
1126
+ });
1127
+ }
1128
+
1129
+ /**
1130
+ * 取消绑定事件
1131
+ * @param element 需要取消绑定的元素|元素数组
1132
+ * @param eventType 需要取消监听的事件
1133
+ * @param callback 通过DOMUtils.on绑定的事件函数
1134
+ * @param option
1135
+ * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
1136
+ * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
1137
+ * @example
1138
+ * // 取消监听元素a.xx的click事件
1139
+ * DOMUtils.off(document.querySelector("a.xx"),"click")
1140
+ * DOMUtils.off("a.xx","click")
1141
+ */
1142
+ off<T extends Event>(
1143
+ element:
1144
+ | HTMLElement
1145
+ | string
1146
+ | NodeList
1147
+ | HTMLElement[]
1148
+ | Window
1149
+ | Document
1150
+ | Element
1151
+ | null
1152
+ | typeof globalThis,
1153
+ eventType: DOMUtils_EventType | DOMUtils_EventType[],
1154
+ callback?: (event: T) => void,
1155
+ option?: boolean | AddEventListenerOptions,
1156
+ filter?: (
1157
+ value: DOMUtilsEventListenerOptionsAttribute,
1158
+ index: number,
1159
+ array: DOMUtilsEventListenerOptionsAttribute[]
1160
+ ) => boolean
1161
+ ): void;
1162
+ /**
1163
+ * 取消绑定事件
1164
+ * @param element 需要取消绑定的元素|元素数组
1165
+ * @param eventType 需要取消监听的事件
1166
+ * @param callback 通过DOMUtils.on绑定的事件函数
1167
+ * @param option
1168
+ * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
1169
+ * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
1170
+ * @example
1171
+ * // 取消监听元素a.xx的click事件
1172
+ * DOMUtils.off(document.querySelector("a.xx"),"click")
1173
+ * DOMUtils.off("a.xx","click")
1174
+ */
1175
+ off<T extends Event>(
1176
+ element:
1177
+ | HTMLElement
1178
+ | string
1179
+ | NodeList
1180
+ | HTMLElement[]
1181
+ | Window
1182
+ | Document
1183
+ | Element
1184
+ | null
1185
+ | typeof globalThis,
1186
+ eventType: string,
1187
+ callback?: (event: T) => void,
1188
+ option?: boolean | AddEventListenerOptions,
1189
+ filter?: (
1190
+ value: DOMUtilsEventListenerOptionsAttribute,
1191
+ index: number,
1192
+ array: DOMUtilsEventListenerOptionsAttribute[]
1193
+ ) => boolean
1194
+ ): void;
1195
+ /**
1196
+ * 取消绑定事件
1197
+ * @param element 需要取消绑定的元素|元素数组
1198
+ * @param eventType 需要取消监听的事件
1199
+ * @param selector 子元素选择器
1200
+ * @param callback 通过DOMUtils.on绑定的事件函数
1201
+ * @param option
1202
+ * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
1203
+ * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
1204
+ * @example
1205
+ * // 取消监听元素a.xx的click、tap、hover事件
1206
+ * DOMUtils.off(document.querySelector("a.xx"),"click tap hover")
1207
+ * DOMUtils.off("a.xx",["click","tap","hover"])
1208
+ */
1209
+ off<T extends Event>(
1210
+ element:
1211
+ | HTMLElement
1212
+ | string
1213
+ | NodeList
1214
+ | HTMLElement[]
1215
+ | Window
1216
+ | Document
1217
+ | Element
1218
+ | null
1219
+ | typeof globalThis,
1220
+ eventType: DOMUtils_EventType | DOMUtils_EventType[],
1221
+ selector?: string | undefined,
1222
+ callback?: (event: T) => void,
1223
+ option?: boolean | AddEventListenerOptions,
1224
+ filter?: (
1225
+ value: DOMUtilsEventListenerOptionsAttribute,
1226
+ index: number,
1227
+ array: DOMUtilsEventListenerOptionsAttribute[]
1228
+ ) => boolean
1229
+ ): void;
1230
+ /**
1231
+ * 取消绑定事件
1232
+ * @param element 需要取消绑定的元素|元素数组
1233
+ * @param eventType 需要取消监听的事件
1234
+ * @param selector 子元素选择器
1235
+ * @param callback 通过DOMUtils.on绑定的事件函数
1236
+ * @param option
1237
+ * + capture 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
1238
+ * @param filter (可选)过滤函数,对元素属性上的事件进行过滤出想要删除的事件
1239
+ * @example
1240
+ * // 取消监听元素a.xx的click、tap、hover事件
1241
+ * DOMUtils.off(document.querySelector("a.xx"),"click tap hover")
1242
+ * DOMUtils.off("a.xx",["click","tap","hover"])
1243
+ */
1244
+ off<T extends Event>(
1245
+ element:
1246
+ | HTMLElement
1247
+ | string
1248
+ | NodeList
1249
+ | HTMLElement[]
1250
+ | Window
1251
+ | Document
1252
+ | Element
1253
+ | null
1254
+ | typeof globalThis,
1255
+ eventType: string,
1256
+ selector?: string | undefined,
1257
+ callback?: (event: T) => void,
1258
+ option?: boolean | AddEventListenerOptions,
1259
+ filter?: (
1260
+ value: DOMUtilsEventListenerOptionsAttribute,
1261
+ index: number,
1262
+ array: DOMUtilsEventListenerOptionsAttribute[]
1263
+ ) => boolean
1264
+ ): void;
1265
+ off<T extends Event>(
1266
+ element:
1267
+ | HTMLElement
1268
+ | string
1269
+ | NodeList
1270
+ | HTMLElement[]
1271
+ | Window
1272
+ | Document
1273
+ | Element
1274
+ | null
1275
+ | typeof globalThis,
1276
+ eventType: DOMUtils_EventType | DOMUtils_EventType[] | string,
1277
+ selector?: string | undefined | ((event: T) => void),
1278
+ callback?: ((event: T) => void) | boolean | AddEventListenerOptions,
1279
+ option?:
1280
+ | boolean
1281
+ | AddEventListenerOptions
1282
+ | ((
1283
+ value: DOMUtilsEventListenerOptionsAttribute,
1284
+ index: number,
1285
+ array: DOMUtilsEventListenerOptionsAttribute[]
1286
+ ) => boolean),
1287
+ filter?: (
1288
+ value: DOMUtilsEventListenerOptionsAttribute,
1289
+ index: number,
1290
+ array: DOMUtilsEventListenerOptionsAttribute[]
1291
+ ) => boolean
1292
+ ) {
1293
+ /**
1294
+ * 获取option配置
1295
+ * @param args1
1296
+ * @param startIndex
1297
+ * @param option
1298
+ */
1299
+ function getOption(
1300
+ args1: IArguments,
1301
+ startIndex: number,
1302
+ option: EventListenerOptions
1303
+ ) {
1304
+ if (typeof args1[startIndex] === "boolean") {
1305
+ option.capture = args1[startIndex];
1306
+ } else if (
1307
+ typeof args1[startIndex] === "object" &&
1308
+ "capture" in args1[startIndex]
1309
+ ) {
1310
+ option.capture = args1[startIndex].capture;
1311
+ }
1312
+ return option;
1313
+ }
1314
+
1315
+ let args = arguments;
1316
+ if (typeof element === "string") {
1317
+ element = document.querySelectorAll(element);
1318
+ }
1319
+ if (element == null) {
1320
+ return;
1321
+ }
1322
+ let elementList: HTMLElement[] = [];
1323
+ if (element instanceof NodeList || Array.isArray(element)) {
1324
+ element = element as HTMLElement[];
1325
+ elementList = [...element];
1326
+ } else {
1327
+ elementList.push(element as HTMLElement);
1328
+ }
1329
+ let eventTypeList: string[] = [];
1330
+ if (Array.isArray(eventType)) {
1331
+ eventTypeList = eventTypeList.concat(eventType as string[]);
1332
+ } else if (typeof eventType === "string") {
1333
+ eventTypeList = eventTypeList.concat(eventType.split(" "));
1334
+ }
1335
+ /**
1336
+ * 子元素选择器
1337
+ */
1338
+ let _selector_: string | undefined = selector as any;
1339
+ /**
1340
+ * 事件的回调函数
1341
+ */
1342
+ let _callback_: (event: T) => void = callback as any;
1343
+
1344
+ /**
1345
+ * 事件的配置
1346
+ */
1347
+ let _option_: EventListenerOptions = {
1348
+ capture: false,
1349
+ };
1350
+ if (typeof selector === "function") {
1351
+ /* 这是为没有selector的情况 */
1352
+ _selector_ = void 0;
1353
+ _callback_ = selector;
1354
+ _option_ = getOption(args, 3, _option_);
1355
+ } else {
1356
+ _option_ = getOption(args, 4, _option_);
1357
+ }
1358
+ elementList.forEach((elementItem) => {
1359
+ /* 获取对象上的事件 */
1360
+ let elementEvents = (elementItem as any)[DOMUtilsData.SymbolEvents] || {};
1361
+ eventTypeList.forEach((eventName) => {
1362
+ let handlers: DOMUtilsEventListenerOptionsAttribute[] =
1363
+ elementEvents[eventName] || [];
1364
+ if (typeof filter === "function") {
1365
+ handlers = handlers.filter(filter);
1366
+ }
1367
+ for (let index = 0; index < handlers.length; index++) {
1368
+ let handler = handlers[index];
1369
+ let flag = false;
1370
+ if (!_selector_ || handler.selector === _selector_) {
1371
+ /* selector不为空,进行selector判断 */
1372
+ flag = true;
1373
+ }
1374
+ if (
1375
+ !_callback_ ||
1376
+ handler.callback === _callback_ ||
1377
+ handler.originCallBack === _callback_
1378
+ ) {
1379
+ /* callback不为空,进行callback判断 */
1380
+ flag = true;
1381
+ }
1382
+
1383
+ if (flag) {
1384
+ elementItem.removeEventListener(
1385
+ eventName,
1386
+ handler.callback,
1387
+ _option_
1388
+ );
1389
+ handlers.splice(index--, 1);
1390
+ }
1391
+ }
1392
+ if (handlers.length === 0) {
1393
+ /* 如果没有任意的handler,那么删除该属性 */
1394
+ CommonDOMUtils.delete(elementEvents, eventType);
1395
+ }
1396
+ });
1397
+ (elementItem as any)[DOMUtilsData.SymbolEvents] = elementEvents;
1398
+ });
1399
+ }
1400
+
1401
+ /**
1402
+ * 取消绑定所有的事件
1403
+ * @param element 需要取消绑定的元素|元素数组
1404
+ * @param eventType (可选)需要取消监听的事件
1405
+ */
1406
+ offAll(
1407
+ element:
1408
+ | HTMLElement
1409
+ | string
1410
+ | NodeList
1411
+ | HTMLElement[]
1412
+ | Window
1413
+ | Element
1414
+ | null,
1415
+ eventType?: string
1416
+ ): void;
1417
+ /**
1418
+ * 取消绑定所有的事件
1419
+ * @param element 需要取消绑定的元素|元素数组
1420
+ * @param eventType (可选)需要取消监听的事件
1421
+ */
1422
+ offAll(
1423
+ element:
1424
+ | HTMLElement
1425
+ | string
1426
+ | NodeList
1427
+ | HTMLElement[]
1428
+ | Window
1429
+ | Element
1430
+ | null,
1431
+ eventType?: DOMUtils_EventType | DOMUtils_EventType[]
1432
+ ): void;
1433
+ /**
1434
+ * 取消绑定所有的事件
1435
+ * @param element 需要取消绑定的元素|元素数组
1436
+ * @param eventType (可选)需要取消监听的事件
1437
+ */
1438
+ offAll(
1439
+ element:
1440
+ | HTMLElement
1441
+ | string
1442
+ | NodeList
1443
+ | HTMLElement[]
1444
+ | Window
1445
+ | Element
1446
+ | null,
1447
+ eventType?: DOMUtils_EventType | DOMUtils_EventType[] | string
1448
+ ) {
1449
+ if (typeof element === "string") {
1450
+ element = document.querySelectorAll(element);
1451
+ }
1452
+ if (element == null) {
1453
+ return;
1454
+ }
1455
+ let elementList: HTMLElement[] = [];
1456
+ if (element instanceof NodeList || Array.isArray(element)) {
1457
+ element = element as HTMLElement[];
1458
+ elementList = [...element];
1459
+ } else {
1460
+ elementList.push(element as HTMLElement);
1461
+ }
1462
+
1463
+ let eventTypeList: string[] = [];
1464
+ if (Array.isArray(eventType)) {
1465
+ eventTypeList = eventTypeList.concat(eventType as string[]);
1466
+ } else if (typeof eventType === "string") {
1467
+ eventTypeList = eventTypeList.concat(eventType.split(" "));
1468
+ }
1469
+ elementList.forEach((elementItem) => {
1470
+ Object.getOwnPropertySymbols(elementItem).forEach((symbolEvents) => {
1471
+ if (!symbolEvents.toString().startsWith("Symbol(events_")) {
1472
+ return;
1473
+ }
1474
+ let elementEvents = (elementItem as any)[symbolEvents] || {};
1475
+ let iterEventNameList = eventTypeList.length
1476
+ ? eventTypeList
1477
+ : Object.keys(elementEvents);
1478
+ iterEventNameList.forEach((eventName) => {
1479
+ let handlers = elementEvents[eventName];
1480
+ if (!handlers) {
1481
+ return;
1482
+ }
1483
+ for (const handler of handlers) {
1484
+ elementItem.removeEventListener(eventName, handler.callback, {
1485
+ capture: handler["option"]["capture"],
1486
+ });
1487
+ }
1488
+ CommonDOMUtils.delete((elementItem as any)[symbolEvents], eventName);
1489
+ });
1490
+ });
1491
+ });
1492
+ }
1493
+ /**
1494
+ * 主动触发事件
1495
+ * @param element 需要触发的元素|元素数组|window
1496
+ * @param eventType 需要触发的事件
1497
+ * @param details 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
1498
+ * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true
1499
+ * @example
1500
+ * // 触发元素a.xx的click事件
1501
+ * DOMUtils.trigger(document.querySelector("a.xx"),"click")
1502
+ * DOMUtils.trigger("a.xx","click")
1503
+ * // 触发元素a.xx的click、tap、hover事件
1504
+ * DOMUtils.trigger(document.querySelector("a.xx"),"click tap hover")
1505
+ * DOMUtils.trigger("a.xx",["click","tap","hover"])
1506
+ */
1507
+ trigger(
1508
+ element: HTMLElement | string | NodeList | any[] | Window | Document,
1509
+ eventType: string,
1510
+ details?: object,
1511
+ useDispatchToTriggerEvent?: boolean
1512
+ ): void;
1513
+ /**
1514
+ * 主动触发事件
1515
+ * @param element 需要触发的元素|元素数组|window
1516
+ * @param eventType 需要触发的事件
1517
+ * @param details 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
1518
+ * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true
1519
+ * @example
1520
+ * // 触发元素a.xx的click事件
1521
+ * DOMUtils.trigger(document.querySelector("a.xx"),"click")
1522
+ * DOMUtils.trigger("a.xx","click")
1523
+ * // 触发元素a.xx的click、tap、hover事件
1524
+ * DOMUtils.trigger(document.querySelector("a.xx"),"click tap hover")
1525
+ * DOMUtils.trigger("a.xx",["click","tap","hover"])
1526
+ */
1527
+ trigger(
1528
+ element: HTMLElement | string | NodeList | any[] | Window | Document,
1529
+ eventType: DOMUtils_EventType | DOMUtils_EventType[],
1530
+ details?: object,
1531
+ useDispatchToTriggerEvent?: boolean
1532
+ ): void;
1533
+ /**
1534
+ * 主动触发事件
1535
+ * @param element 需要触发的元素|元素数组|window
1536
+ * @param eventType 需要触发的事件
1537
+ * @param details 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
1538
+ * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true
1539
+ * @example
1540
+ * // 触发元素a.xx的click事件
1541
+ * DOMUtils.trigger(document.querySelector("a.xx"),"click")
1542
+ * DOMUtils.trigger("a.xx","click")
1543
+ * // 触发元素a.xx的click、tap、hover事件
1544
+ * DOMUtils.trigger(document.querySelector("a.xx"),"click tap hover")
1545
+ * DOMUtils.trigger("a.xx",["click","tap","hover"])
1546
+ */
1547
+ trigger(
1548
+ element: HTMLElement | string | NodeList | any[] | Window | Document,
1549
+ eventType: DOMUtils_EventType | DOMUtils_EventType[] | string,
1550
+ details?: object,
1551
+ useDispatchToTriggerEvent: boolean = true
1552
+ ) {
1553
+ if (typeof element === "string") {
1554
+ element = document.querySelector(element) as HTMLElement;
1555
+ }
1556
+ if (element == null) {
1557
+ return;
1558
+ }
1559
+ let elementList = [];
1560
+ if (element instanceof NodeList || Array.isArray(element)) {
1561
+ element = element as HTMLElement[];
1562
+ elementList = [...element];
1563
+ } else {
1564
+ elementList = [element];
1565
+ }
1566
+ let eventTypeList: string[] = [];
1567
+ if (Array.isArray(eventType)) {
1568
+ eventTypeList = eventType as string[];
1569
+ } else if (typeof eventType === "string") {
1570
+ eventTypeList = eventType.split(" ");
1571
+ }
1572
+
1573
+ elementList.forEach((elementItem) => {
1574
+ /* 获取对象上的事件 */
1575
+ let events = elementItem[DOMUtilsData.SymbolEvents] || {};
1576
+ eventTypeList.forEach((_eventType_) => {
1577
+ let event: Event = null as any;
1578
+ if (details && details instanceof Event) {
1579
+ event = details;
1580
+ } else {
1581
+ event = new Event(_eventType_);
1582
+ if (details) {
1583
+ Object.keys(details).forEach((keyName) => {
1584
+ (event as any)[keyName] = (details as any)[keyName];
1585
+ });
1586
+ }
1587
+ }
1588
+ if (useDispatchToTriggerEvent == false && _eventType_ in events) {
1589
+ events[_eventType_].forEach((eventsItem: any) => {
1590
+ eventsItem.callback(event);
1591
+ });
1592
+ } else {
1593
+ elementItem.dispatchEvent(event);
1594
+ }
1595
+ });
1596
+ });
1597
+ }
1598
+
1599
+ /**
1600
+ * 获取元素相对于文档的偏移坐标(加上文档的滚动条)
1601
+ * @param element 目标元素
1602
+ * @example
1603
+ * // 获取元素a.xx的对于文档的偏移坐标
1604
+ * DOMUtils.offset(document.querySelector("a.xx"))
1605
+ * DOMUtils.offset("a.xx")
1606
+ * > 0
1607
+ */
1608
+ offset(element: HTMLElement | string) {
1609
+ if (typeof element === "string") {
1610
+ element = document.querySelector(element) as HTMLElement;
1611
+ }
1612
+ if (element == null) {
1613
+ return;
1614
+ }
1615
+ let rect = element.getBoundingClientRect();
1616
+ return {
1617
+ /** y轴偏移 */
1618
+ top: rect.top + globalThis.scrollY,
1619
+ /** x轴偏移 */
1620
+ left: rect.left + globalThis.scrollX,
1621
+ };
1622
+ }
1623
+ /**
1624
+ * 获取元素的宽度
1625
+ * @param element 要获取宽度的元素
1626
+ * @param isShow 是否已进行isShow,避免爆堆栈
1627
+ * @returns 元素的宽度,单位为像素
1628
+ * @example
1629
+ * // 获取元素a.xx的宽度
1630
+ * DOMUtils.width(document.querySelector("a.xx"))
1631
+ * DOMUtils.width("a.xx")
1632
+ * > 100
1633
+ * // 获取window的宽度
1634
+ * DOMUtils.width(window)
1635
+ * > 400
1636
+ * @example
1637
+ * // 设置元素a.xx的宽度为200
1638
+ * DOMUtils.width(document.querySelector("a.xx"),200)
1639
+ * DOMUtils.width("a.xx",200)
1640
+ */
1641
+ width(
1642
+ element: HTMLElement | string | Window | Document,
1643
+ isShow?: boolean
1644
+ ): number;
1645
+ width(
1646
+ element: HTMLElement | string | Window | Document,
1647
+ isShow: boolean = false
1648
+ ) {
1649
+ let DOMUtilsContext = this;
1650
+ if (typeof element === "string") {
1651
+ element = document.querySelector(element) as HTMLElement;
1652
+ }
1653
+ if (element == null) {
1654
+ return;
1655
+ }
1656
+ if (CommonDOMUtils.isWin(element)) {
1657
+ return window.document.documentElement.clientWidth;
1658
+ }
1659
+ if ((element as HTMLElement).nodeType === 9) {
1660
+ /* Document文档节点 */
1661
+ element = element as Document;
1662
+ return Math.max(
1663
+ element.body.scrollWidth,
1664
+ element.documentElement.scrollWidth,
1665
+ element.body.offsetWidth,
1666
+ element.documentElement.offsetWidth,
1667
+ element.documentElement.clientWidth
1668
+ );
1669
+ }
1670
+ if (isShow || (!isShow && CommonDOMUtils.isShow(element as HTMLElement))) {
1671
+ /* 已显示 */
1672
+ /* 不从style中获取对应的宽度,因为可能使用了class定义了width !important */
1673
+ element = element as HTMLElement;
1674
+ /* 如果element.style.width为空 则从css里面获取是否定义了width信息如果定义了 则读取css里面定义的宽度width */
1675
+ if (
1676
+ parseFloat(CommonDOMUtils.getStyleValue(element, "width").toString()) >
1677
+ 0
1678
+ ) {
1679
+ return parseFloat(
1680
+ CommonDOMUtils.getStyleValue(element, "width").toString()
1681
+ );
1682
+ }
1683
+
1684
+ /* 如果从css里获取到的值不是大于0 可能是auto 则通过offsetWidth来进行计算 */
1685
+ if (element.offsetWidth > 0) {
1686
+ let borderLeftWidth = CommonDOMUtils.getStyleValue(
1687
+ element,
1688
+ "borderLeftWidth"
1689
+ );
1690
+ let borderRightWidth = CommonDOMUtils.getStyleValue(
1691
+ element,
1692
+ "borderRightWidth"
1693
+ );
1694
+ let paddingLeft = CommonDOMUtils.getStyleValue(element, "paddingLeft");
1695
+ let paddingRight = CommonDOMUtils.getStyleValue(
1696
+ element,
1697
+ "paddingRight"
1698
+ );
1699
+ let backHeight =
1700
+ parseFloat(element.offsetWidth.toString()) -
1701
+ parseFloat(borderLeftWidth.toString()) -
1702
+ parseFloat(borderRightWidth.toString()) -
1703
+ parseFloat(paddingLeft.toString()) -
1704
+ parseFloat(paddingRight.toString());
1705
+ return parseFloat(backHeight.toString());
1706
+ }
1707
+ return 0;
1708
+ } else {
1709
+ /* 未显示 */
1710
+ element = element as HTMLElement;
1711
+ let { recovery } = CommonDOMUtils.showElement(element);
1712
+ let width = DOMUtilsContext.width(element, true);
1713
+ recovery();
1714
+ return width;
1715
+ }
1716
+ }
1717
+
1718
+ /**
1719
+ * 获取元素的高度
1720
+ * @param element 要获取高度的元素
1721
+ * @param isShow 是否已进行isShow,避免爆堆栈
1722
+ * @returns 元素的高度,单位为像素
1723
+ * @example
1724
+ * // 获取元素a.xx的高度
1725
+ * DOMUtils.height(document.querySelector("a.xx"))
1726
+ * DOMUtils.height("a.xx")
1727
+ * > 100
1728
+ * // 获取window的高度
1729
+ * DOMUtils.height(window)
1730
+ * > 700
1731
+ * @example
1732
+ * // 设置元素a.xx的高度为200
1733
+ * DOMUtils.height(document.querySelector("a.xx"),200)
1734
+ * DOMUtils.height("a.xx",200)
1735
+ */
1736
+ height(
1737
+ element: HTMLElement | string | Window | Document,
1738
+ isShow?: boolean
1739
+ ): number;
1740
+ height(
1741
+ element: HTMLElement | string | Window | Document,
1742
+ isShow: boolean = false
1743
+ ) {
1744
+ let DOMUtilsContext = this;
1745
+ if (CommonDOMUtils.isWin(element)) {
1746
+ return window.document.documentElement.clientHeight;
1747
+ }
1748
+ if (typeof element === "string") {
1749
+ element = document.querySelector(element) as HTMLElement;
1750
+ }
1751
+ if (element == null) {
1752
+ // @ts-ignore
1753
+ return;
1754
+ }
1755
+ if ((element as Document).nodeType === 9) {
1756
+ element = element as Document;
1757
+ /* Document文档节点 */
1758
+ return Math.max(
1759
+ element.body.scrollHeight,
1760
+ element.documentElement.scrollHeight,
1761
+ element.body.offsetHeight,
1762
+ element.documentElement.offsetHeight,
1763
+ element.documentElement.clientHeight
1764
+ );
1765
+ }
1766
+ if (isShow || (!isShow && CommonDOMUtils.isShow(element as HTMLElement))) {
1767
+ element = element as HTMLElement;
1768
+ /* 已显示 */
1769
+ /* 从style中获取对应的高度,因为可能使用了class定义了width !important */
1770
+ /* 如果element.style.height为空 则从css里面获取是否定义了height信息如果定义了 则读取css里面定义的高度height */
1771
+ if (
1772
+ parseFloat(CommonDOMUtils.getStyleValue(element, "height").toString()) >
1773
+ 0
1774
+ ) {
1775
+ return parseFloat(
1776
+ CommonDOMUtils.getStyleValue(element, "height").toString()
1777
+ );
1778
+ }
1779
+
1780
+ /* 如果从css里获取到的值不是大于0 可能是auto 则通过offsetHeight来进行计算 */
1781
+ if (element.offsetHeight > 0) {
1782
+ let borderTopWidth = CommonDOMUtils.getStyleValue(
1783
+ element,
1784
+ "borderTopWidth"
1785
+ );
1786
+ let borderBottomWidth = CommonDOMUtils.getStyleValue(
1787
+ element,
1788
+ "borderBottomWidth"
1789
+ );
1790
+ let paddingTop = CommonDOMUtils.getStyleValue(element, "paddingTop");
1791
+ let paddingBottom = CommonDOMUtils.getStyleValue(
1792
+ element,
1793
+ "paddingBottom"
1794
+ );
1795
+ let backHeight =
1796
+ parseFloat(element.offsetHeight.toString()) -
1797
+ parseFloat(borderTopWidth.toString()) -
1798
+ parseFloat(borderBottomWidth.toString()) -
1799
+ parseFloat(paddingTop.toString()) -
1800
+ parseFloat(paddingBottom.toString());
1801
+ return parseFloat(backHeight.toString());
1802
+ }
1803
+ return 0;
1804
+ } else {
1805
+ /* 未显示 */
1806
+ element = element as HTMLElement;
1807
+ let { recovery } = CommonDOMUtils.showElement(element);
1808
+ let height = DOMUtilsContext.height(element, true);
1809
+ recovery();
1810
+ return height;
1811
+ }
1812
+ }
1813
+ /**
1814
+ * 获取元素的外部宽度(包括边框和外边距)
1815
+ * @param {HTMLElement|string} element 要获取外部宽度的元素
1816
+ * @param {boolean} [isShow=false] 是否已进行isShow,避免爆堆栈
1817
+ * @returns {number} 元素的外部宽度,单位为像素
1818
+ * @example
1819
+ * // 获取元素a.xx的外部宽度
1820
+ * DOMUtils.outerWidth(document.querySelector("a.xx"))
1821
+ * DOMUtils.outerWidth("a.xx")
1822
+ * > 100
1823
+ * // 获取window的外部宽度
1824
+ * DOMUtils.outerWidth(window)
1825
+ * > 400
1826
+ */
1827
+ outerWidth(
1828
+ element: HTMLElement | string | Window | Document,
1829
+ isShow?: boolean
1830
+ ): number;
1831
+ outerWidth(
1832
+ element: HTMLElement | string | Window | Document,
1833
+ isShow: boolean = false
1834
+ ) {
1835
+ let DOMUtilsContext = this;
1836
+ if (CommonDOMUtils.isWin(element)) {
1837
+ return window.innerWidth;
1838
+ }
1839
+ if (typeof element === "string") {
1840
+ element = document.querySelector(element) as HTMLElement;
1841
+ }
1842
+ if (element == null) {
1843
+ // @ts-ignore
1844
+ return;
1845
+ }
1846
+ element = element as HTMLElement;
1847
+ if (isShow || (!isShow && CommonDOMUtils.isShow(element))) {
1848
+ let style = getComputedStyle(element, null);
1849
+ let marginLeft = CommonDOMUtils.getStyleValue(style, "marginLeft");
1850
+ let marginRight = CommonDOMUtils.getStyleValue(style, "marginRight");
1851
+ return element.offsetWidth + marginLeft + marginRight;
1852
+ } else {
1853
+ let { recovery } = CommonDOMUtils.showElement(element);
1854
+ let outerWidth = DOMUtilsContext.outerWidth(element, true);
1855
+ recovery();
1856
+ return outerWidth;
1857
+ }
1858
+ }
1859
+ /**
1860
+ * 获取元素的外部高度(包括边框和外边距)
1861
+ * @param {HTMLElement|string} element 要获取外部高度的元素
1862
+ * @param {boolean} [isShow=false] 是否已进行isShow,避免爆堆栈
1863
+ * @returns {number} 元素的外部高度,单位为像素
1864
+ * @example
1865
+ * // 获取元素a.xx的外部高度
1866
+ * DOMUtils.outerHeight(document.querySelector("a.xx"))
1867
+ * DOMUtils.outerHeight("a.xx")
1868
+ * > 100
1869
+ * // 获取window的外部高度
1870
+ * DOMUtils.outerHeight(window)
1871
+ * > 700
1872
+ */
1873
+ outerHeight(element: HTMLElement | string | Window, isShow?: boolean): number;
1874
+ outerHeight(
1875
+ element: HTMLElement | string | Window,
1876
+ isShow: boolean = false
1877
+ ): number {
1878
+ let DOMUtilsContext = this;
1879
+ if (CommonDOMUtils.isWin(element)) {
1880
+ return window.innerHeight;
1881
+ }
1882
+ if (typeof element === "string") {
1883
+ element = document.querySelector(element) as HTMLElement;
1884
+ }
1885
+ if (element == null) {
1886
+ // @ts-ignore
1887
+ return;
1888
+ }
1889
+ element = element as HTMLElement;
1890
+ if (isShow || (!isShow && CommonDOMUtils.isShow(element))) {
1891
+ let style = getComputedStyle(element, null);
1892
+ let marginTop = CommonDOMUtils.getStyleValue(style, "marginTop");
1893
+ let marginBottom = CommonDOMUtils.getStyleValue(style, "marginBottom");
1894
+ return element.offsetHeight + marginTop + marginBottom;
1895
+ } else {
1896
+ let { recovery } = CommonDOMUtils.showElement(element);
1897
+ let outerHeight = DOMUtilsContext.outerHeight(element, true);
1898
+ recovery();
1899
+ return outerHeight;
1900
+ }
1901
+ }
1902
+
1903
+ /**
1904
+ * 等待文档加载完成后执行指定的函数
1905
+ * @param callback 需要执行的函数
1906
+ * @example
1907
+ * DOMUtils.ready(function(){
1908
+ * console.log("文档加载完毕")
1909
+ * })
1910
+ */
1911
+ ready(callback: () => void) {
1912
+ let DOMUtilsContext = this;
1913
+ function completed() {
1914
+ DOMUtilsContext.off(document, "DOMContentLoaded", completed);
1915
+ DOMUtilsContext.off(globalThis, "load", completed);
1916
+ callback();
1917
+ }
1918
+ if (
1919
+ document.readyState === "complete" ||
1920
+ (document.readyState !== "loading" &&
1921
+ !(document.documentElement as any).doScroll)
1922
+ ) {
1923
+ setTimeout(callback);
1924
+ } else {
1925
+ /* 监听DOMContentLoaded事件 */
1926
+ DOMUtilsContext.on(document, "DOMContentLoaded", completed);
1927
+ /* 监听load事件 */
1928
+ DOMUtilsContext.on(globalThis, "load", completed);
1929
+ }
1930
+ }
1931
+ /**
1932
+ * 在一定时间内改变元素的样式属性,实现动画效果
1933
+ * @param element 需要进行动画的元素
1934
+ * @param styles 动画结束时元素的样式属性
1935
+ * @param duration 动画持续时间,单位为毫秒
1936
+ * @param callback 动画结束后执行的函数
1937
+ * @example
1938
+ * // 监听元素a.xx的从显示变为隐藏
1939
+ * DOMUtils.animate(document.querySelector("a.xx"),{ top:100},1000,function(){
1940
+ * console.log("已往上位移100px")
1941
+ * })
1942
+ */
1943
+ animate(
1944
+ element: HTMLElement | string,
1945
+ styles: CSSStyleDeclaration,
1946
+ duration: number = 1000,
1947
+ callback: (() => void) | undefined | null = null
1948
+ ) {
1949
+ if (typeof element === "string") {
1950
+ element = document.querySelector(element) as HTMLElement;
1951
+ }
1952
+ if (element == null) {
1953
+ return;
1954
+ }
1955
+ if (typeof duration !== "number" || duration <= 0) {
1956
+ throw new TypeError("duration must be a positive number");
1957
+ }
1958
+ if (typeof callback !== "function" && callback !== void 0) {
1959
+ throw new TypeError("callback must be a function or null");
1960
+ }
1961
+ if (typeof styles !== "object" || styles === void 0) {
1962
+ throw new TypeError("styles must be an object");
1963
+ }
1964
+ if (Object.keys(styles).length === 0) {
1965
+ throw new Error("styles must contain at least one property");
1966
+ }
1967
+ let start = performance.now();
1968
+ let from: {
1969
+ [prop: string]: any;
1970
+ } = {};
1971
+ let to: {
1972
+ [prop: string]: any;
1973
+ } = {};
1974
+ for (let prop in styles) {
1975
+ from[prop] = element.style[prop] || getComputedStyle(element)[prop];
1976
+ to[prop] = styles[prop];
1977
+ }
1978
+ let timer = setInterval(function () {
1979
+ let timePassed = performance.now() - start;
1980
+ let progress = timePassed / duration;
1981
+ if (progress > 1) {
1982
+ progress = 1;
1983
+ }
1984
+ for (let prop in styles) {
1985
+ element.style[prop] =
1986
+ from[prop] + (to[prop] - from[prop]) * progress + "px";
1987
+ }
1988
+ if (progress === 1) {
1989
+ clearInterval(timer);
1990
+ if (callback) {
1991
+ callback();
1992
+ }
1993
+ }
1994
+ }, 10);
1995
+ }
1996
+ /**
1997
+ * 将一个元素包裹在指定的HTML元素中
1998
+ * @param element 要包裹的元素
1999
+ * @param wrapperHTML 要包裹的HTML元素的字符串表示形式
2000
+ * @example
2001
+ * // 将a.xx元素外面包裹一层div
2002
+ * DOMUtils.wrap(document.querySelector("a.xx"),"<div></div>")
2003
+ */
2004
+ wrap(element: HTMLElement | string | Node, wrapperHTML: string) {
2005
+ if (typeof element === "string") {
2006
+ element = document.querySelector(element) as HTMLElement;
2007
+ }
2008
+ if (element == null) {
2009
+ return;
2010
+ }
2011
+ element = element as HTMLElement;
2012
+ // 创建一个新的div元素,并将wrapperHTML作为其innerHTML
2013
+ let wrapper = document.createElement("div");
2014
+ wrapper.innerHTML = wrapperHTML;
2015
+
2016
+ let wrapperFirstChild = wrapper.firstChild as HTMLElement;
2017
+ // 将要包裹的元素插入目标元素前面
2018
+ (element.parentElement as HTMLElement).insertBefore(
2019
+ wrapperFirstChild,
2020
+ element
2021
+ );
2022
+
2023
+ // 将要包裹的元素移动到wrapper中
2024
+ wrapperFirstChild.appendChild(element);
2025
+ }
2026
+ /**
2027
+ * 获取当前元素的前一个兄弟元素
2028
+ * @param element 当前元素
2029
+ * @returns 前一个兄弟元素
2030
+ * @example
2031
+ * // 获取a.xx元素前一个兄弟元素
2032
+ * DOMUtils.prev(document.querySelector("a.xx"))
2033
+ * DOMUtils.prev("a.xx")
2034
+ * > <div ...>....</div>
2035
+ */
2036
+ prev(element: HTMLElement | string): HTMLElement;
2037
+ prev(element: HTMLElement | string) {
2038
+ if (typeof element === "string") {
2039
+ element = document.querySelector(element) as HTMLElement;
2040
+ }
2041
+ if (element == null) {
2042
+ return;
2043
+ }
2044
+ return element.previousElementSibling as HTMLElement;
2045
+ }
2046
+
2047
+ /**
2048
+ * 获取当前元素的后一个兄弟元素
2049
+ * @param element 当前元素
2050
+ * @returns 后一个兄弟元素
2051
+ * @example
2052
+ * // 获取a.xx元素前一个兄弟元素
2053
+ * DOMUtils.next(document.querySelector("a.xx"))
2054
+ * DOMUtils.next("a.xx")
2055
+ * > <div ...>....</div>
2056
+ */
2057
+ next(element: HTMLElement | string): HTMLElement;
2058
+ next(element: HTMLElement | string) {
2059
+ if (typeof element === "string") {
2060
+ element = document.querySelector(element) as HTMLElement;
2061
+ }
2062
+ if (element == null) {
2063
+ return;
2064
+ }
2065
+ return element.nextElementSibling as HTMLElement;
2066
+ }
2067
+ /**
2068
+ * 取消挂载在window下的DOMUtils并返回DOMUtils
2069
+ * @example
2070
+ * let DOMUtils = window.DOMUtils.noConflict()
2071
+ */
2072
+ noConflict() {
2073
+ if ((window as any).DOMUtils) {
2074
+ CommonDOMUtils.delete(window, "DOMUtils");
2075
+ }
2076
+ (window as any).DOMUtils = this;
2077
+ return this;
2078
+ }
2079
+ /**
2080
+ * 获取当前元素的所有兄弟元素
2081
+ * @param element 当前元素
2082
+ * @returns 所有兄弟元素
2083
+ * @example
2084
+ * // 获取a.xx元素所有兄弟元素
2085
+ * DOMUtils.siblings(document.querySelector("a.xx"))
2086
+ * DOMUtils.siblings("a.xx")
2087
+ * > (3) [div.logo-wrapper, div.forum-block, div.more-btn-desc]
2088
+ */
2089
+ siblings(element: HTMLElement | string): HTMLElement[];
2090
+ siblings(element: HTMLElement | string) {
2091
+ if (typeof element === "string") {
2092
+ element = document.querySelector(element) as HTMLElement;
2093
+ }
2094
+ if (element == null) {
2095
+ return;
2096
+ }
2097
+ return Array.from(
2098
+ (element.parentElement as HTMLElement)
2099
+ .children as HTMLCollectionOf<HTMLElement>
2100
+ ).filter((child) => child !== element);
2101
+ }
2102
+ /**
2103
+ * 获取当前元素的父元素
2104
+ * @param element 当前元素
2105
+ * @returns 父元素
2106
+ * @example
2107
+ * // 获取a.xx元素的父元素
2108
+ * DOMUtils.parent(document.querySelector("a.xx"))
2109
+ * DOMUtils.parent("a.xx")
2110
+ * > <div ...>....</div>
2111
+ */
2112
+ parent(element: HTMLElement | string): HTMLElement;
2113
+ /**
2114
+ * 获取当前元素的父元素
2115
+ * @param element 当前元素
2116
+ * @returns 父元素
2117
+ * @example
2118
+ * // 获取a.xx元素的父元素
2119
+ * DOMUtils.parent(document.querySelector("a.xx"))
2120
+ * DOMUtils.parent("a.xx")
2121
+ * > <div ...>....</div>
2122
+ */
2123
+ parent(element: HTMLElement[] | NodeList): HTMLElement[];
2124
+ /**
2125
+ * 获取当前元素的父元素
2126
+ * @param element 当前元素
2127
+ * @returns 父元素
2128
+ * @example
2129
+ * // 获取a.xx元素的父元素
2130
+ * DOMUtils.parent(document.querySelector("a.xx"))
2131
+ * DOMUtils.parent("a.xx")
2132
+ * > <div ...>....</div>
2133
+ */
2134
+ parent(element: HTMLElement | NodeList | string | HTMLElement[]) {
2135
+ let DOMUtilsContext = this;
2136
+ if (typeof element === "string") {
2137
+ element = document.querySelector(element) as HTMLElement;
2138
+ }
2139
+ if (element == null) {
2140
+ return;
2141
+ }
2142
+ if (element instanceof NodeList || element instanceof Array) {
2143
+ element = element as HTMLElement[];
2144
+ let resultArray: HTMLElement[] = [];
2145
+ element.forEach((eleItem) => {
2146
+ resultArray.push(DOMUtilsContext.parent(eleItem));
2147
+ });
2148
+ return resultArray;
2149
+ } else {
2150
+ return element.parentElement;
2151
+ }
2152
+ }
2153
+ /**
2154
+ * 将字符串转为Element元素
2155
+ * @param html
2156
+ * @param useParser (可选)是否使用DOMParser来生成元素,有些时候通过DOMParser生成的元素有点问题
2157
+ * + true 使用DOMPraser来转换字符串
2158
+ * + false 创建一个div,里面放入字符串,然后提取firstChild
2159
+ * @param isComplete (可选)是否是完整的
2160
+ * + true 如果useParser为true,那么返回整个使用DOMParser转换成的Document
2161
+ * 如果useParser为false,返回一个DIV元素,DIV元素内包裹着需要转换的字符串
2162
+ * + false 如果useParser为true,那么返回整个使用DOMParser转换成的Document的body
2163
+ * 如果useParser为false,返回一个DIV元素的firstChild
2164
+ * @example
2165
+ * // 将字符串转为Element元素
2166
+ * DOMUtils.parseHTML("<a href='xxxx'></a>")
2167
+ * > <a href="xxxx"></a>
2168
+ * @example
2169
+ * // 使用DOMParser将字符串转为Element元素
2170
+ * DOMUtils.parseHTML("<a href='xxxx'></a>",true)
2171
+ * > <a href="xxxx"></a>
2172
+ * @example
2173
+ * // 由于需要转换的元素是多个元素,将字符串转为完整的Element元素
2174
+ * DOMUtils.parseHTML("<a href='xxxx'></a><a href='xxxx'></a>",false, true)
2175
+ * > <div><a href="xxxx"></a><a href='xxxx'></a></div>
2176
+ * @example
2177
+ * // 由于需要转换的元素是多个元素,使用DOMParser将字符串转为完整的Element元素
2178
+ * DOMUtils.parseHTML("<a href='xxxx'></a><a href='xxxx'></a>",true, true)
2179
+ * > #document
2180
+ */
2181
+ parseHTML<T1 extends boolean, T2 extends boolean>(
2182
+ html: string,
2183
+ useParser?: T1,
2184
+ isComplete?: T2
2185
+ ): ParseHTMLReturnType<T1, T2>;
2186
+ parseHTML(html: string, useParser = false, isComplete = false) {
2187
+ function parseHTMLByDOMParser() {
2188
+ let parser = new DOMParser();
2189
+ if (isComplete) {
2190
+ return parser.parseFromString(html, "text/html");
2191
+ } else {
2192
+ return parser.parseFromString(html, "text/html").body.firstChild;
2193
+ }
2194
+ }
2195
+ function parseHTMLByCreateDom() {
2196
+ let tempDIV = document.createElement("div");
2197
+ tempDIV.innerHTML = html;
2198
+ if (isComplete) {
2199
+ return tempDIV;
2200
+ } else {
2201
+ return tempDIV.firstChild;
2202
+ }
2203
+ }
2204
+ if (useParser) {
2205
+ return parseHTMLByDOMParser();
2206
+ } else {
2207
+ return parseHTMLByCreateDom();
2208
+ }
2209
+ }
2210
+ /**
2211
+ * 当鼠标移入或移出元素时触发事件
2212
+ * @param element 当前元素
2213
+ * @param handler 事件处理函数
2214
+ * @param option 配置
2215
+ * @example
2216
+ * // 监听a.xx元素的移入或移出
2217
+ * DOMUtils.hover(document.querySelector("a.xx"),()=>{
2218
+ * console.log("移入/移除");
2219
+ * })
2220
+ * DOMUtils.hover("a.xx",()=>{
2221
+ * console.log("移入/移除");
2222
+ * })
2223
+ */
2224
+ hover(
2225
+ element: HTMLElement | string,
2226
+ handler: (event: Event) => void,
2227
+ option?: boolean | AddEventListenerOptions
2228
+ ) {
2229
+ let DOMUtilsContext = this;
2230
+ if (typeof element === "string") {
2231
+ element = document.querySelector(element) as HTMLElement;
2232
+ }
2233
+ if (element == null) {
2234
+ return;
2235
+ }
2236
+ DOMUtilsContext.on(element, "mouseenter", null, handler, option);
2237
+ DOMUtilsContext.on(element, "mouseleave", null, handler, option);
2238
+ }
2239
+ /**
2240
+ * 显示元素
2241
+ * @param target 当前元素
2242
+ * @example
2243
+ * // 显示a.xx元素
2244
+ * DOMUtils.show(document.querySelector("a.xx"))
2245
+ * DOMUtils.show(document.querySelectorAll("a.xx"))
2246
+ * DOMUtils.show("a.xx")
2247
+ */
2248
+ show(target: HTMLElement | string | NodeList | HTMLElement[]) {
2249
+ let DOMUtilsContext = this;
2250
+ if (target == null) {
2251
+ return;
2252
+ }
2253
+ if (typeof target === "string") {
2254
+ target = document.querySelectorAll(target);
2255
+ }
2256
+ if (target instanceof NodeList || target instanceof Array) {
2257
+ target = target as HTMLElement[];
2258
+ for (const element of target) {
2259
+ DOMUtilsContext.show(element);
2260
+ }
2261
+ } else {
2262
+ target.style.display = "";
2263
+ if (!CommonDOMUtils.isShow(target)) {
2264
+ /* 仍然是不显示,尝试使用强覆盖 */
2265
+ target.style.setProperty("display", "unset", "important");
2266
+ }
2267
+ }
2268
+ }
2269
+ /**
2270
+ * 隐藏元素
2271
+ * @param target 当前元素
2272
+ * @example
2273
+ * // 隐藏a.xx元素
2274
+ * DOMUtils.hide(document.querySelector("a.xx"))
2275
+ * DOMUtils.hide(document.querySelectorAll("a.xx"))
2276
+ * DOMUtils.hide("a.xx")
2277
+ */
2278
+ hide(target: HTMLElement | string | NodeList | HTMLElement[]) {
2279
+ let DOMUtilsContext = this;
2280
+ if (target == null) {
2281
+ return;
2282
+ }
2283
+ if (typeof target === "string") {
2284
+ target = document.querySelectorAll(target);
2285
+ }
2286
+ if (target instanceof NodeList || target instanceof Array) {
2287
+ target = target as HTMLElement[];
2288
+ for (const element of target) {
2289
+ DOMUtilsContext.hide(element);
2290
+ }
2291
+ } else {
2292
+ target.style.display = "none";
2293
+ if (CommonDOMUtils.isShow(target)) {
2294
+ /* 仍然是显示,尝试使用强覆盖 */
2295
+ target.style.setProperty("display", "none", "important");
2296
+ }
2297
+ }
2298
+ }
2299
+ /**
2300
+ * 当按键松开时触发事件
2301
+ * keydown - > keypress - > keyup
2302
+ * @param target 当前元素
2303
+ * @param handler 事件处理函数
2304
+ * @param option 配置
2305
+ * @example
2306
+ * // 监听a.xx元素的按键松开
2307
+ * DOMUtils.keyup(document.querySelector("a.xx"),()=>{
2308
+ * console.log("按键松开");
2309
+ * })
2310
+ * DOMUtils.keyup("a.xx",()=>{
2311
+ * console.log("按键松开");
2312
+ * })
2313
+ */
2314
+ keyup(
2315
+ target: HTMLElement | string | Window | typeof globalThis,
2316
+ handler: (event: KeyboardEvent) => void,
2317
+ option?: boolean | AddEventListenerOptions
2318
+ ) {
2319
+ let DOMUtilsContext = this;
2320
+ if (target == null) {
2321
+ return;
2322
+ }
2323
+ if (typeof target === "string") {
2324
+ target = document.querySelector(target) as HTMLElement;
2325
+ }
2326
+ DOMUtilsContext.on(target, "keyup", null, handler, option);
2327
+ }
2328
+ /**
2329
+ * 当按键按下时触发事件
2330
+ * keydown - > keypress - > keyup
2331
+ * @param target 目标
2332
+ * @param handler 事件处理函数
2333
+ * @param option 配置
2334
+ * @example
2335
+ * // 监听a.xx元素的按键按下
2336
+ * DOMUtils.keydown(document.querySelector("a.xx"),()=>{
2337
+ * console.log("按键按下");
2338
+ * })
2339
+ * DOMUtils.keydown("a.xx",()=>{
2340
+ * console.log("按键按下");
2341
+ * })
2342
+ */
2343
+ keydown(
2344
+ target: HTMLElement | Window | typeof globalThis | string,
2345
+ handler: (event: KeyboardEvent) => void,
2346
+ option?: boolean | AddEventListenerOptions
2347
+ ) {
2348
+ let DOMUtilsContext = this;
2349
+ if (target == null) {
2350
+ return;
2351
+ }
2352
+ if (typeof target === "string") {
2353
+ target = document.querySelector(target) as HTMLElement;
2354
+ }
2355
+ DOMUtilsContext.on(target, "keydown", null, handler, option);
2356
+ }
2357
+ /**
2358
+ * 当按键按下时触发事件
2359
+ * keydown - > keypress - > keyup
2360
+ * @param target 目标
2361
+ * @param handler 事件处理函数
2362
+ * @param option 配置
2363
+ * @example
2364
+ * // 监听a.xx元素的按键按下
2365
+ * DOMUtils.keypress(document.querySelector("a.xx"),()=>{
2366
+ * console.log("按键按下");
2367
+ * })
2368
+ * DOMUtils.keypress("a.xx",()=>{
2369
+ * console.log("按键按下");
2370
+ * })
2371
+ */
2372
+ keypress(
2373
+ target: HTMLElement | Window | typeof globalThis | string,
2374
+ handler: (event: KeyboardEvent) => void,
2375
+ option?: boolean | AddEventListenerOptions
2376
+ ) {
2377
+ let DOMUtilsContext = this;
2378
+ if (target == null) {
2379
+ return;
2380
+ }
2381
+ if (typeof target === "string") {
2382
+ target = document.querySelector(target) as HTMLElement;
2383
+ }
2384
+ DOMUtilsContext.on(target, "keypress", null, handler, option);
2385
+ }
2386
+ /**
2387
+ * 淡入元素
2388
+ * @param element 当前元素
2389
+ * @param duration 动画持续时间(毫秒),默认400毫秒
2390
+ * @param callback 动画结束的回调
2391
+ * @example
2392
+ * // 元素a.xx淡入
2393
+ * DOMUtils.fadeIn(document.querySelector("a.xx"),2500,()=>{
2394
+ * console.log("淡入完毕");
2395
+ * })
2396
+ * DOMUtils.fadeIn("a.xx",undefined,()=>{
2397
+ * console.log("淡入完毕");
2398
+ * })
2399
+ */
2400
+ fadeIn(
2401
+ element: HTMLElement | string,
2402
+ duration: number = 400,
2403
+ callback?: () => void
2404
+ ) {
2405
+ if (element == null) {
2406
+ return;
2407
+ }
2408
+ if (typeof element === "string") {
2409
+ element = document.querySelector(element) as HTMLElement;
2410
+ }
2411
+ element = element as HTMLElement;
2412
+ element.style.opacity = "0";
2413
+ element.style.display = "";
2414
+ let start: number = null as any;
2415
+ let timer: number = null as any;
2416
+ function step(timestamp: number) {
2417
+ if (!start) start = timestamp;
2418
+ let progress = timestamp - start;
2419
+ element = element as HTMLElement;
2420
+ element.style.opacity = Math.min(progress / duration, 1).toString();
2421
+ if (progress < duration) {
2422
+ window.requestAnimationFrame(step);
2423
+ } else {
2424
+ if (callback && typeof callback === "function") {
2425
+ callback();
2426
+ }
2427
+ window.cancelAnimationFrame(timer);
2428
+ }
2429
+ }
2430
+ timer = window.requestAnimationFrame(step);
2431
+ }
2432
+ /**
2433
+ * 淡出元素
2434
+ * @param element 当前元素
2435
+ * @param duration 动画持续时间(毫秒),默认400毫秒
2436
+ * @param callback 动画结束的回调
2437
+ * @example
2438
+ * // 元素a.xx淡出
2439
+ * DOMUtils.fadeOut(document.querySelector("a.xx"),2500,()=>{
2440
+ * console.log("淡出完毕");
2441
+ * })
2442
+ * DOMUtils.fadeOut("a.xx",undefined,()=>{
2443
+ * console.log("淡出完毕");
2444
+ * })
2445
+ */
2446
+ fadeOut(
2447
+ element: HTMLElement | string,
2448
+ duration: number = 400,
2449
+ callback?: () => void
2450
+ ) {
2451
+ if (element == null) {
2452
+ return;
2453
+ }
2454
+ if (typeof element === "string") {
2455
+ element = document.querySelector(element) as HTMLElement;
2456
+ }
2457
+ element = element as HTMLElement;
2458
+ element.style.opacity = "1";
2459
+ let start: number = null as any;
2460
+ let timer: number = null as any;
2461
+ function step(timestamp: number) {
2462
+ if (!start) start = timestamp;
2463
+ let progress = timestamp - start;
2464
+ element = element as HTMLElement;
2465
+ element.style.opacity = Math.max(1 - progress / duration, 0).toString();
2466
+ if (progress < duration) {
2467
+ window.requestAnimationFrame(step);
2468
+ } else {
2469
+ element.style.display = "none";
2470
+ if (typeof callback === "function") {
2471
+ callback();
2472
+ }
2473
+ window.cancelAnimationFrame(timer);
2474
+ }
2475
+ }
2476
+ timer = window.requestAnimationFrame(step);
2477
+ }
2478
+ /**
2479
+ * 切换元素的显示和隐藏状态
2480
+ * @param element 当前元素
2481
+ * @example
2482
+ * // 如果元素a.xx当前是隐藏,则显示,如果是显示,则隐藏
2483
+ * DOMUtils.toggle(document.querySelector("a.xx"))
2484
+ * DOMUtils.toggle("a.xx")
2485
+ */
2486
+ toggle(element: HTMLElement | string) {
2487
+ let DOMUtilsContext = this;
2488
+ if (typeof element === "string") {
2489
+ element = document.querySelector(element) as HTMLElement;
2490
+ }
2491
+ if (element == null) {
2492
+ return;
2493
+ }
2494
+ if (getComputedStyle(element).getPropertyValue("display") === "none") {
2495
+ DOMUtilsContext.show(element);
2496
+ } else {
2497
+ DOMUtilsContext.hide(element);
2498
+ }
2499
+ }
2500
+ }
2501
+
2502
+ let domUtils = new DOMUtils();
2503
+
2504
+ export { domUtils as DOMUtils };