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