@whitesev/pops 2.4.6 → 2.4.7

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