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