a2bei4-utils 1.0.0 → 1.0.1
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/LICENSE +21 -21
- package/README.md +2 -2
- package/dist/a2bei4.utils.cjs.js +1051 -250
- package/dist/a2bei4.utils.cjs.js.map +1 -1
- package/dist/a2bei4.utils.cjs.min.js +1 -1
- package/dist/a2bei4.utils.cjs.min.js.map +1 -1
- package/dist/a2bei4.utils.esm.js +1047 -251
- package/dist/a2bei4.utils.esm.js.map +1 -1
- package/dist/a2bei4.utils.esm.min.js +1 -1
- package/dist/a2bei4.utils.esm.min.js.map +1 -1
- package/dist/a2bei4.utils.umd.js +1051 -250
- package/dist/a2bei4.utils.umd.js.map +1 -1
- package/dist/a2bei4.utils.umd.min.js +1 -1
- package/dist/a2bei4.utils.umd.min.js.map +1 -1
- package/dist/arr.cjs +27 -27
- package/dist/arr.cjs.map +1 -1
- package/dist/arr.js +27 -27
- package/dist/arr.js.map +1 -1
- package/dist/audio.cjs +281 -0
- package/dist/audio.cjs.map +1 -0
- package/dist/audio.js +278 -0
- package/dist/audio.js.map +1 -0
- package/dist/common.cjs +6 -6
- package/dist/common.cjs.map +1 -1
- package/dist/common.js +6 -6
- package/dist/common.js.map +1 -1
- package/dist/download.cjs +43 -0
- package/dist/download.cjs.map +1 -1
- package/dist/download.js +43 -1
- package/dist/download.js.map +1 -1
- package/dist/evt.cjs +148 -148
- package/dist/evt.cjs.map +1 -1
- package/dist/evt.js +148 -148
- package/dist/evt.js.map +1 -1
- package/dist/id.cjs +68 -68
- package/dist/id.cjs.map +1 -1
- package/dist/id.js +68 -68
- package/dist/id.js.map +1 -1
- package/dist/timer.cjs +0 -1
- package/dist/timer.cjs.map +1 -1
- package/dist/timer.js +0 -1
- package/dist/timer.js.map +1 -1
- package/dist/tree.cjs +75 -0
- package/dist/tree.cjs.map +1 -1
- package/dist/tree.js +75 -1
- package/dist/tree.js.map +1 -1
- package/dist/webSocket.cjs +409 -0
- package/dist/webSocket.cjs.map +1 -0
- package/dist/webSocket.js +407 -0
- package/dist/webSocket.js.map +1 -0
- package/package.json +11 -1
- package/readme.txt +8 -5
- package/types/audio.d.ts +57 -0
- package/types/download.d.ts +12 -1
- package/types/index.d.ts +207 -1
- package/types/tree.d.ts +17 -1
- package/types/webSocket.d.ts +124 -0
package/dist/evt.cjs
CHANGED
|
@@ -1,153 +1,153 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* 简单、高性能的通用事件总线。
|
|
5
|
-
* - 支持命名空间事件
|
|
6
|
-
* - 支持一次性监听器
|
|
7
|
-
* - 返回唯一 flag,用于精确卸载
|
|
8
|
-
* - emit 时可选自定义 this 指向
|
|
9
|
-
*/
|
|
10
|
-
class MyEvent {
|
|
11
|
-
constructor() {
|
|
12
|
-
this.evtPool = new Map();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* 注册事件监听器。
|
|
17
|
-
* @param {string} name - 事件名
|
|
18
|
-
* @param {Function} fn - 回调函数
|
|
19
|
-
* @returns {string} flag - 唯一标识,用于 off
|
|
20
|
-
*/
|
|
21
|
-
on(name, fn) {
|
|
22
|
-
let flag = Date.now() + "_" + parseInt(Math.random() * 1e8);
|
|
23
|
-
const evtItem = {
|
|
24
|
-
flag,
|
|
25
|
-
fn
|
|
26
|
-
};
|
|
27
|
-
if (this.evtPool.has(name)) {
|
|
28
|
-
this.evtPool.get(name).push(evtItem);
|
|
29
|
-
} else {
|
|
30
|
-
this.evtPool.set(name, [evtItem]);
|
|
31
|
-
}
|
|
32
|
-
return flag;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 注册一次性监听器,触发后自动移除。
|
|
37
|
-
* @param {string} name - 事件名
|
|
38
|
-
* @param {Function} fn - 回调函数
|
|
39
|
-
* @returns {string} flag - 唯一标识
|
|
40
|
-
*/
|
|
41
|
-
once(name, fn) {
|
|
42
|
-
const _this = this;
|
|
43
|
-
let wrapper;
|
|
44
|
-
wrapper = function (data) {
|
|
45
|
-
_this.off(name, wrapper);
|
|
46
|
-
fn.call(this, data);
|
|
47
|
-
};
|
|
48
|
-
return this.on(name, wrapper);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* 移除指定事件监听器。
|
|
53
|
-
* @param {string} name - 事件名
|
|
54
|
-
* @param {Function|string} fnOrFlag - 回调函数或 flag
|
|
55
|
-
*/
|
|
56
|
-
off(name, fnOrFlag) {
|
|
57
|
-
if (!this.evtPool.has(name)) return;
|
|
58
|
-
const evtItems = this.evtPool.get(name);
|
|
59
|
-
const filtered = evtItems.filter((item) => item.fn !== fnOrFlag && item.flag !== fnOrFlag);
|
|
60
|
-
if (filtered.length === 0) {
|
|
61
|
-
this.evtPool.delete(name);
|
|
62
|
-
} else {
|
|
63
|
-
this.evtPool.set(name, filtered);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 触发事件(同步执行)。
|
|
69
|
-
* @param {string} name - 事件名
|
|
70
|
-
* @param {*} [data] - 任意载荷
|
|
71
|
-
* @param {*} [fnThis] - 回调内部 this 指向,默认 undefined
|
|
72
|
-
*/
|
|
73
|
-
emit(name, data, fnThis) {
|
|
74
|
-
if (!this.evtPool.has(name)) return;
|
|
75
|
-
const evtItems = this.evtPool.get(name);
|
|
76
|
-
evtItems.forEach((item) => {
|
|
77
|
-
try {
|
|
78
|
-
item.fn.call(fnThis, data);
|
|
79
|
-
} catch (err) {
|
|
80
|
-
console.error(`Error in event listener for "${name}":`, err);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* 跨页通信插件:通过 localStorage + storage 事件将当前实例的 emit 广播到其他同源页面。
|
|
88
|
-
* 支持节流、命名空间隔离。
|
|
89
|
-
*/
|
|
90
|
-
const MyEvent_CrossPagePlugin = (() => {
|
|
91
|
-
const INSTALLED = new WeakSet(); // 防止重复安装
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
/**
|
|
95
|
-
* 为指定 MyEvent 实例安装跨页插件。
|
|
96
|
-
* @param {MyEvent} bus - 事件总线实例
|
|
97
|
-
* @param {Options} [opts] - 配置项
|
|
98
|
-
*/
|
|
99
|
-
install(bus, opts = {}) {
|
|
100
|
-
if (INSTALLED.has(bus)) return;
|
|
101
|
-
INSTALLED.add(bus);
|
|
102
|
-
|
|
103
|
-
const ns = `___my-event-cross-page-${opts.namespace || "default"}___`;
|
|
104
|
-
const delay = opts.throttle || 16;
|
|
105
|
-
let last = 0;
|
|
106
|
-
|
|
107
|
-
// 1、重写 emit
|
|
108
|
-
const rawEmit = bus.emit;
|
|
109
|
-
bus.emit = function (name, data, fnThis) {
|
|
110
|
-
rawEmit.call(bus, name, data, fnThis); // 本地先执行
|
|
111
|
-
const now = Date.now();
|
|
112
|
-
if (now - last < delay) return;
|
|
113
|
-
last = now;
|
|
114
|
-
const key = ns + name;
|
|
115
|
-
try {
|
|
116
|
-
localStorage.setItem(key, JSON.stringify({ name, data, ts: now }));
|
|
117
|
-
localStorage.removeItem(key); // 触发 storage 事件
|
|
118
|
-
} catch (e) {}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// 2、监听其他页广播
|
|
122
|
-
function onStorageHandler(e) {
|
|
123
|
-
if (!e.key || !e.key.startsWith(ns)) return;
|
|
124
|
-
let payload;
|
|
125
|
-
try {
|
|
126
|
-
payload = JSON.parse(e.newValue || "{}");
|
|
127
|
-
} catch {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
if (!payload.ts || payload.ts <= last) return;
|
|
131
|
-
rawEmit.call(bus, e.key.slice(ns.length), payload.data); // 仅本地
|
|
132
|
-
}
|
|
133
|
-
addEventListener("storage", onStorageHandler);
|
|
134
|
-
|
|
135
|
-
// 3、保存卸载器
|
|
136
|
-
bus._uninstallCrossPage = () => {
|
|
137
|
-
removeEventListener("storage", onStorageHandler);
|
|
138
|
-
bus.emit = rawEmit;
|
|
139
|
-
INSTALLED.delete(bus);
|
|
140
|
-
};
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* 卸载插件,恢复原始 emit 并停止监听。
|
|
145
|
-
* @param {MyEvent} bus - 事件总线实例
|
|
146
|
-
*/
|
|
147
|
-
uninstall(bus) {
|
|
148
|
-
if (typeof bus._uninstallCrossPage === "function") bus._uninstallCrossPage();
|
|
149
|
-
}
|
|
150
|
-
};
|
|
3
|
+
/**
|
|
4
|
+
* 简单、高性能的通用事件总线。
|
|
5
|
+
* - 支持命名空间事件
|
|
6
|
+
* - 支持一次性监听器
|
|
7
|
+
* - 返回唯一 flag,用于精确卸载
|
|
8
|
+
* - emit 时可选自定义 this 指向
|
|
9
|
+
*/
|
|
10
|
+
class MyEvent {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.evtPool = new Map();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 注册事件监听器。
|
|
17
|
+
* @param {string} name - 事件名
|
|
18
|
+
* @param {Function} fn - 回调函数
|
|
19
|
+
* @returns {string} flag - 唯一标识,用于 off
|
|
20
|
+
*/
|
|
21
|
+
on(name, fn) {
|
|
22
|
+
let flag = Date.now() + "_" + parseInt(Math.random() * 1e8);
|
|
23
|
+
const evtItem = {
|
|
24
|
+
flag,
|
|
25
|
+
fn
|
|
26
|
+
};
|
|
27
|
+
if (this.evtPool.has(name)) {
|
|
28
|
+
this.evtPool.get(name).push(evtItem);
|
|
29
|
+
} else {
|
|
30
|
+
this.evtPool.set(name, [evtItem]);
|
|
31
|
+
}
|
|
32
|
+
return flag;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 注册一次性监听器,触发后自动移除。
|
|
37
|
+
* @param {string} name - 事件名
|
|
38
|
+
* @param {Function} fn - 回调函数
|
|
39
|
+
* @returns {string} flag - 唯一标识
|
|
40
|
+
*/
|
|
41
|
+
once(name, fn) {
|
|
42
|
+
const _this = this;
|
|
43
|
+
let wrapper;
|
|
44
|
+
wrapper = function (data) {
|
|
45
|
+
_this.off(name, wrapper);
|
|
46
|
+
fn.call(this, data);
|
|
47
|
+
};
|
|
48
|
+
return this.on(name, wrapper);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 移除指定事件监听器。
|
|
53
|
+
* @param {string} name - 事件名
|
|
54
|
+
* @param {Function|string} fnOrFlag - 回调函数或 flag
|
|
55
|
+
*/
|
|
56
|
+
off(name, fnOrFlag) {
|
|
57
|
+
if (!this.evtPool.has(name)) return;
|
|
58
|
+
const evtItems = this.evtPool.get(name);
|
|
59
|
+
const filtered = evtItems.filter((item) => item.fn !== fnOrFlag && item.flag !== fnOrFlag);
|
|
60
|
+
if (filtered.length === 0) {
|
|
61
|
+
this.evtPool.delete(name);
|
|
62
|
+
} else {
|
|
63
|
+
this.evtPool.set(name, filtered);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 触发事件(同步执行)。
|
|
69
|
+
* @param {string} name - 事件名
|
|
70
|
+
* @param {*} [data] - 任意载荷
|
|
71
|
+
* @param {*} [fnThis] - 回调内部 this 指向,默认 undefined
|
|
72
|
+
*/
|
|
73
|
+
emit(name, data, fnThis) {
|
|
74
|
+
if (!this.evtPool.has(name)) return;
|
|
75
|
+
const evtItems = this.evtPool.get(name);
|
|
76
|
+
evtItems.forEach((item) => {
|
|
77
|
+
try {
|
|
78
|
+
item.fn.call(fnThis, data);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
console.error(`Error in event listener for "${name}":`, err);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 跨页通信插件:通过 localStorage + storage 事件将当前实例的 emit 广播到其他同源页面。
|
|
88
|
+
* 支持节流、命名空间隔离。
|
|
89
|
+
*/
|
|
90
|
+
const MyEvent_CrossPagePlugin = (() => {
|
|
91
|
+
const INSTALLED = new WeakSet(); // 防止重复安装
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
/**
|
|
95
|
+
* 为指定 MyEvent 实例安装跨页插件。
|
|
96
|
+
* @param {MyEvent} bus - 事件总线实例
|
|
97
|
+
* @param {Options} [opts] - 配置项
|
|
98
|
+
*/
|
|
99
|
+
install(bus, opts = {}) {
|
|
100
|
+
if (INSTALLED.has(bus)) return;
|
|
101
|
+
INSTALLED.add(bus);
|
|
102
|
+
|
|
103
|
+
const ns = `___my-event-cross-page-${opts.namespace || "default"}___`;
|
|
104
|
+
const delay = opts.throttle || 16;
|
|
105
|
+
let last = 0;
|
|
106
|
+
|
|
107
|
+
// 1、重写 emit
|
|
108
|
+
const rawEmit = bus.emit;
|
|
109
|
+
bus.emit = function (name, data, fnThis) {
|
|
110
|
+
rawEmit.call(bus, name, data, fnThis); // 本地先执行
|
|
111
|
+
const now = Date.now();
|
|
112
|
+
if (now - last < delay) return;
|
|
113
|
+
last = now;
|
|
114
|
+
const key = ns + name;
|
|
115
|
+
try {
|
|
116
|
+
localStorage.setItem(key, JSON.stringify({ name, data, ts: now }));
|
|
117
|
+
localStorage.removeItem(key); // 触发 storage 事件
|
|
118
|
+
} catch (e) {}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// 2、监听其他页广播
|
|
122
|
+
function onStorageHandler(e) {
|
|
123
|
+
if (!e.key || !e.key.startsWith(ns)) return;
|
|
124
|
+
let payload;
|
|
125
|
+
try {
|
|
126
|
+
payload = JSON.parse(e.newValue || "{}");
|
|
127
|
+
} catch {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (!payload.ts || payload.ts <= last) return;
|
|
131
|
+
rawEmit.call(bus, e.key.slice(ns.length), payload.data); // 仅本地
|
|
132
|
+
}
|
|
133
|
+
addEventListener("storage", onStorageHandler);
|
|
134
|
+
|
|
135
|
+
// 3、保存卸载器
|
|
136
|
+
bus._uninstallCrossPage = () => {
|
|
137
|
+
removeEventListener("storage", onStorageHandler);
|
|
138
|
+
bus.emit = rawEmit;
|
|
139
|
+
INSTALLED.delete(bus);
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* 卸载插件,恢复原始 emit 并停止监听。
|
|
145
|
+
* @param {MyEvent} bus - 事件总线实例
|
|
146
|
+
*/
|
|
147
|
+
uninstall(bus) {
|
|
148
|
+
if (typeof bus._uninstallCrossPage === "function") bus._uninstallCrossPage();
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
151
|
})();
|
|
152
152
|
|
|
153
153
|
exports.MyEvent = MyEvent;
|
package/dist/evt.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evt.cjs","sources":["../src/source/evt.js"],"sourcesContent":["/**\
|
|
1
|
+
{"version":3,"file":"evt.cjs","sources":["../src/source/evt.js"],"sourcesContent":["/**\n * 简单、高性能的通用事件总线。\n * - 支持命名空间事件\n * - 支持一次性监听器\n * - 返回唯一 flag,用于精确卸载\n * - emit 时可选自定义 this 指向\n */\nexport class MyEvent {\n constructor() {\n this.evtPool = new Map();\n }\n\n /**\n * 注册事件监听器。\n * @param {string} name - 事件名\n * @param {Function} fn - 回调函数\n * @returns {string} flag - 唯一标识,用于 off\n */\n on(name, fn) {\n let flag = Date.now() + \"_\" + parseInt(Math.random() * 1e8);\n const evtItem = {\n flag,\n fn\n };\n if (this.evtPool.has(name)) {\n this.evtPool.get(name).push(evtItem);\n } else {\n this.evtPool.set(name, [evtItem]);\n }\n return flag;\n }\n\n /**\n * 注册一次性监听器,触发后自动移除。\n * @param {string} name - 事件名\n * @param {Function} fn - 回调函数\n * @returns {string} flag - 唯一标识\n */\n once(name, fn) {\n const _this = this;\n let wrapper;\n wrapper = function (data) {\n _this.off(name, wrapper);\n fn.call(this, data);\n };\n return this.on(name, wrapper);\n }\n\n /**\n * 移除指定事件监听器。\n * @param {string} name - 事件名\n * @param {Function|string} fnOrFlag - 回调函数或 flag\n */\n off(name, fnOrFlag) {\n if (!this.evtPool.has(name)) return;\n const evtItems = this.evtPool.get(name);\n const filtered = evtItems.filter((item) => item.fn !== fnOrFlag && item.flag !== fnOrFlag);\n if (filtered.length === 0) {\n this.evtPool.delete(name);\n } else {\n this.evtPool.set(name, filtered);\n }\n }\n\n /**\n * 触发事件(同步执行)。\n * @param {string} name - 事件名\n * @param {*} [data] - 任意载荷\n * @param {*} [fnThis] - 回调内部 this 指向,默认 undefined\n */\n emit(name, data, fnThis) {\n if (!this.evtPool.has(name)) return;\n const evtItems = this.evtPool.get(name);\n evtItems.forEach((item) => {\n try {\n item.fn.call(fnThis, data);\n } catch (err) {\n console.error(`Error in event listener for \"${name}\":`, err);\n }\n });\n }\n}\n\n/**\n * 跨页通信插件:通过 localStorage + storage 事件将当前实例的 emit 广播到其他同源页面。\n * 支持节流、命名空间隔离。\n */\nexport const MyEvent_CrossPagePlugin = (() => {\n const INSTALLED = new WeakSet(); // 防止重复安装\n\n return {\n /**\n * 为指定 MyEvent 实例安装跨页插件。\n * @param {MyEvent} bus - 事件总线实例\n * @param {Options} [opts] - 配置项\n */\n install(bus, opts = {}) {\n if (INSTALLED.has(bus)) return;\n INSTALLED.add(bus);\n\n const ns = `___my-event-cross-page-${opts.namespace || \"default\"}___`;\n const delay = opts.throttle || 16;\n let last = 0;\n\n // 1、重写 emit\n const rawEmit = bus.emit;\n bus.emit = function (name, data, fnThis) {\n rawEmit.call(bus, name, data, fnThis); // 本地先执行\n const now = Date.now();\n if (now - last < delay) return;\n last = now;\n const key = ns + name;\n try {\n localStorage.setItem(key, JSON.stringify({ name, data, ts: now }));\n localStorage.removeItem(key); // 触发 storage 事件\n } catch (e) {}\n };\n\n // 2、监听其他页广播\n function onStorageHandler(e) {\n if (!e.key || !e.key.startsWith(ns)) return;\n let payload;\n try {\n payload = JSON.parse(e.newValue || \"{}\");\n } catch {\n return;\n }\n if (!payload.ts || payload.ts <= last) return;\n rawEmit.call(bus, e.key.slice(ns.length), payload.data); // 仅本地\n }\n addEventListener(\"storage\", onStorageHandler);\n\n // 3、保存卸载器\n bus._uninstallCrossPage = () => {\n removeEventListener(\"storage\", onStorageHandler);\n bus.emit = rawEmit;\n INSTALLED.delete(bus);\n };\n },\n\n /**\n * 卸载插件,恢复原始 emit 并停止监听。\n * @param {MyEvent} bus - 事件总线实例\n */\n uninstall(bus) {\n if (typeof bus._uninstallCrossPage === \"function\") bus._uninstallCrossPage();\n }\n };\n})();\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,OAAO,CAAC;AACrB,IAAI,WAAW,GAAG;AAClB,QAAQ,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE;AAChC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE;AACjB,QAAQ,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC;AACnE,QAAQ,MAAM,OAAO,GAAG;AACxB,YAAY,IAAI;AAChB,YAAY;AACZ,SAAS;AACT,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACpC,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAChD,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC;AAC7C,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE;AACnB,QAAQ,MAAM,KAAK,GAAG,IAAI;AAC1B,QAAQ,IAAI,OAAO;AACnB,QAAQ,OAAO,GAAG,UAAU,IAAI,EAAE;AAClC,YAAY,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC;AACpC,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;AAC/B,QAAQ,CAAC;AACT,QAAQ,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;AACrC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE;AACxB,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACrC,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAC/C,QAAQ,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC;AAClG,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;AACnC,YAAY,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;AACrC,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC;AAC5C,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;AAC7B,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACrC,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAC/C,QAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK;AACnC,YAAY,IAAI;AAChB,gBAAgB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAC1C,YAAY,CAAC,CAAC,OAAO,GAAG,EAAE;AAC1B,gBAAgB,OAAO,CAAC,KAAK,CAAC,CAAC,6BAA6B,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;AAC5E,YAAY;AACZ,QAAQ,CAAC,CAAC;AACV,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACY,MAAC,uBAAuB,GAAG,CAAC,MAAM;AAC9C,IAAI,MAAM,SAAS,GAAG,IAAI,OAAO,EAAE,CAAC;;AAEpC,IAAI,OAAO;AACX;AACA;AACA;AACA;AACA;AACA,QAAQ,OAAO,CAAC,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE;AAChC,YAAY,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACpC,YAAY,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;;AAE9B,YAAY,MAAM,EAAE,GAAG,CAAC,uBAAuB,EAAE,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC;AACjF,YAAY,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE;AAC7C,YAAY,IAAI,IAAI,GAAG,CAAC;;AAExB;AACA,YAAY,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI;AACpC,YAAY,GAAG,CAAC,IAAI,GAAG,UAAU,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;AACrD,gBAAgB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACtD,gBAAgB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;AACtC,gBAAgB,IAAI,GAAG,GAAG,IAAI,GAAG,KAAK,EAAE;AACxC,gBAAgB,IAAI,GAAG,GAAG;AAC1B,gBAAgB,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI;AACrC,gBAAgB,IAAI;AACpB,oBAAoB,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;AACtF,oBAAoB,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AACjD,gBAAgB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;AAC7B,YAAY,CAAC;;AAEb;AACA,YAAY,SAAS,gBAAgB,CAAC,CAAC,EAAE;AACzC,gBAAgB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE;AACrD,gBAAgB,IAAI,OAAO;AAC3B,gBAAgB,IAAI;AACpB,oBAAoB,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,CAAC;AAC5D,gBAAgB,CAAC,CAAC,MAAM;AACxB,oBAAoB;AACpB,gBAAgB;AAChB,gBAAgB,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,OAAO,CAAC,EAAE,IAAI,IAAI,EAAE;AACvD,gBAAgB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;AACxE,YAAY;AACZ,YAAY,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,CAAC;;AAEzD;AACA,YAAY,GAAG,CAAC,mBAAmB,GAAG,MAAM;AAC5C,gBAAgB,mBAAmB,CAAC,SAAS,EAAE,gBAAgB,CAAC;AAChE,gBAAgB,GAAG,CAAC,IAAI,GAAG,OAAO;AAClC,gBAAgB,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC;AACrC,YAAY,CAAC;AACb,QAAQ,CAAC;;AAET;AACA;AACA;AACA;AACA,QAAQ,SAAS,CAAC,GAAG,EAAE;AACvB,YAAY,IAAI,OAAO,GAAG,CAAC,mBAAmB,KAAK,UAAU,EAAE,GAAG,CAAC,mBAAmB,EAAE;AACxF,QAAQ;AACR,KAAK;AACL,CAAC;;;;;"}
|
package/dist/evt.js
CHANGED
|
@@ -1,151 +1,151 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 简单、高性能的通用事件总线。
|
|
3
|
-
* - 支持命名空间事件
|
|
4
|
-
* - 支持一次性监听器
|
|
5
|
-
* - 返回唯一 flag,用于精确卸载
|
|
6
|
-
* - emit 时可选自定义 this 指向
|
|
7
|
-
*/
|
|
8
|
-
class MyEvent {
|
|
9
|
-
constructor() {
|
|
10
|
-
this.evtPool = new Map();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* 注册事件监听器。
|
|
15
|
-
* @param {string} name - 事件名
|
|
16
|
-
* @param {Function} fn - 回调函数
|
|
17
|
-
* @returns {string} flag - 唯一标识,用于 off
|
|
18
|
-
*/
|
|
19
|
-
on(name, fn) {
|
|
20
|
-
let flag = Date.now() + "_" + parseInt(Math.random() * 1e8);
|
|
21
|
-
const evtItem = {
|
|
22
|
-
flag,
|
|
23
|
-
fn
|
|
24
|
-
};
|
|
25
|
-
if (this.evtPool.has(name)) {
|
|
26
|
-
this.evtPool.get(name).push(evtItem);
|
|
27
|
-
} else {
|
|
28
|
-
this.evtPool.set(name, [evtItem]);
|
|
29
|
-
}
|
|
30
|
-
return flag;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 注册一次性监听器,触发后自动移除。
|
|
35
|
-
* @param {string} name - 事件名
|
|
36
|
-
* @param {Function} fn - 回调函数
|
|
37
|
-
* @returns {string} flag - 唯一标识
|
|
38
|
-
*/
|
|
39
|
-
once(name, fn) {
|
|
40
|
-
const _this = this;
|
|
41
|
-
let wrapper;
|
|
42
|
-
wrapper = function (data) {
|
|
43
|
-
_this.off(name, wrapper);
|
|
44
|
-
fn.call(this, data);
|
|
45
|
-
};
|
|
46
|
-
return this.on(name, wrapper);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 移除指定事件监听器。
|
|
51
|
-
* @param {string} name - 事件名
|
|
52
|
-
* @param {Function|string} fnOrFlag - 回调函数或 flag
|
|
53
|
-
*/
|
|
54
|
-
off(name, fnOrFlag) {
|
|
55
|
-
if (!this.evtPool.has(name)) return;
|
|
56
|
-
const evtItems = this.evtPool.get(name);
|
|
57
|
-
const filtered = evtItems.filter((item) => item.fn !== fnOrFlag && item.flag !== fnOrFlag);
|
|
58
|
-
if (filtered.length === 0) {
|
|
59
|
-
this.evtPool.delete(name);
|
|
60
|
-
} else {
|
|
61
|
-
this.evtPool.set(name, filtered);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* 触发事件(同步执行)。
|
|
67
|
-
* @param {string} name - 事件名
|
|
68
|
-
* @param {*} [data] - 任意载荷
|
|
69
|
-
* @param {*} [fnThis] - 回调内部 this 指向,默认 undefined
|
|
70
|
-
*/
|
|
71
|
-
emit(name, data, fnThis) {
|
|
72
|
-
if (!this.evtPool.has(name)) return;
|
|
73
|
-
const evtItems = this.evtPool.get(name);
|
|
74
|
-
evtItems.forEach((item) => {
|
|
75
|
-
try {
|
|
76
|
-
item.fn.call(fnThis, data);
|
|
77
|
-
} catch (err) {
|
|
78
|
-
console.error(`Error in event listener for "${name}":`, err);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* 跨页通信插件:通过 localStorage + storage 事件将当前实例的 emit 广播到其他同源页面。
|
|
86
|
-
* 支持节流、命名空间隔离。
|
|
87
|
-
*/
|
|
88
|
-
const MyEvent_CrossPagePlugin = (() => {
|
|
89
|
-
const INSTALLED = new WeakSet(); // 防止重复安装
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
/**
|
|
93
|
-
* 为指定 MyEvent 实例安装跨页插件。
|
|
94
|
-
* @param {MyEvent} bus - 事件总线实例
|
|
95
|
-
* @param {Options} [opts] - 配置项
|
|
96
|
-
*/
|
|
97
|
-
install(bus, opts = {}) {
|
|
98
|
-
if (INSTALLED.has(bus)) return;
|
|
99
|
-
INSTALLED.add(bus);
|
|
100
|
-
|
|
101
|
-
const ns = `___my-event-cross-page-${opts.namespace || "default"}___`;
|
|
102
|
-
const delay = opts.throttle || 16;
|
|
103
|
-
let last = 0;
|
|
104
|
-
|
|
105
|
-
// 1、重写 emit
|
|
106
|
-
const rawEmit = bus.emit;
|
|
107
|
-
bus.emit = function (name, data, fnThis) {
|
|
108
|
-
rawEmit.call(bus, name, data, fnThis); // 本地先执行
|
|
109
|
-
const now = Date.now();
|
|
110
|
-
if (now - last < delay) return;
|
|
111
|
-
last = now;
|
|
112
|
-
const key = ns + name;
|
|
113
|
-
try {
|
|
114
|
-
localStorage.setItem(key, JSON.stringify({ name, data, ts: now }));
|
|
115
|
-
localStorage.removeItem(key); // 触发 storage 事件
|
|
116
|
-
} catch (e) {}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// 2、监听其他页广播
|
|
120
|
-
function onStorageHandler(e) {
|
|
121
|
-
if (!e.key || !e.key.startsWith(ns)) return;
|
|
122
|
-
let payload;
|
|
123
|
-
try {
|
|
124
|
-
payload = JSON.parse(e.newValue || "{}");
|
|
125
|
-
} catch {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
if (!payload.ts || payload.ts <= last) return;
|
|
129
|
-
rawEmit.call(bus, e.key.slice(ns.length), payload.data); // 仅本地
|
|
130
|
-
}
|
|
131
|
-
addEventListener("storage", onStorageHandler);
|
|
132
|
-
|
|
133
|
-
// 3、保存卸载器
|
|
134
|
-
bus._uninstallCrossPage = () => {
|
|
135
|
-
removeEventListener("storage", onStorageHandler);
|
|
136
|
-
bus.emit = rawEmit;
|
|
137
|
-
INSTALLED.delete(bus);
|
|
138
|
-
};
|
|
139
|
-
},
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* 卸载插件,恢复原始 emit 并停止监听。
|
|
143
|
-
* @param {MyEvent} bus - 事件总线实例
|
|
144
|
-
*/
|
|
145
|
-
uninstall(bus) {
|
|
146
|
-
if (typeof bus._uninstallCrossPage === "function") bus._uninstallCrossPage();
|
|
147
|
-
}
|
|
148
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* 简单、高性能的通用事件总线。
|
|
3
|
+
* - 支持命名空间事件
|
|
4
|
+
* - 支持一次性监听器
|
|
5
|
+
* - 返回唯一 flag,用于精确卸载
|
|
6
|
+
* - emit 时可选自定义 this 指向
|
|
7
|
+
*/
|
|
8
|
+
class MyEvent {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.evtPool = new Map();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 注册事件监听器。
|
|
15
|
+
* @param {string} name - 事件名
|
|
16
|
+
* @param {Function} fn - 回调函数
|
|
17
|
+
* @returns {string} flag - 唯一标识,用于 off
|
|
18
|
+
*/
|
|
19
|
+
on(name, fn) {
|
|
20
|
+
let flag = Date.now() + "_" + parseInt(Math.random() * 1e8);
|
|
21
|
+
const evtItem = {
|
|
22
|
+
flag,
|
|
23
|
+
fn
|
|
24
|
+
};
|
|
25
|
+
if (this.evtPool.has(name)) {
|
|
26
|
+
this.evtPool.get(name).push(evtItem);
|
|
27
|
+
} else {
|
|
28
|
+
this.evtPool.set(name, [evtItem]);
|
|
29
|
+
}
|
|
30
|
+
return flag;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 注册一次性监听器,触发后自动移除。
|
|
35
|
+
* @param {string} name - 事件名
|
|
36
|
+
* @param {Function} fn - 回调函数
|
|
37
|
+
* @returns {string} flag - 唯一标识
|
|
38
|
+
*/
|
|
39
|
+
once(name, fn) {
|
|
40
|
+
const _this = this;
|
|
41
|
+
let wrapper;
|
|
42
|
+
wrapper = function (data) {
|
|
43
|
+
_this.off(name, wrapper);
|
|
44
|
+
fn.call(this, data);
|
|
45
|
+
};
|
|
46
|
+
return this.on(name, wrapper);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 移除指定事件监听器。
|
|
51
|
+
* @param {string} name - 事件名
|
|
52
|
+
* @param {Function|string} fnOrFlag - 回调函数或 flag
|
|
53
|
+
*/
|
|
54
|
+
off(name, fnOrFlag) {
|
|
55
|
+
if (!this.evtPool.has(name)) return;
|
|
56
|
+
const evtItems = this.evtPool.get(name);
|
|
57
|
+
const filtered = evtItems.filter((item) => item.fn !== fnOrFlag && item.flag !== fnOrFlag);
|
|
58
|
+
if (filtered.length === 0) {
|
|
59
|
+
this.evtPool.delete(name);
|
|
60
|
+
} else {
|
|
61
|
+
this.evtPool.set(name, filtered);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 触发事件(同步执行)。
|
|
67
|
+
* @param {string} name - 事件名
|
|
68
|
+
* @param {*} [data] - 任意载荷
|
|
69
|
+
* @param {*} [fnThis] - 回调内部 this 指向,默认 undefined
|
|
70
|
+
*/
|
|
71
|
+
emit(name, data, fnThis) {
|
|
72
|
+
if (!this.evtPool.has(name)) return;
|
|
73
|
+
const evtItems = this.evtPool.get(name);
|
|
74
|
+
evtItems.forEach((item) => {
|
|
75
|
+
try {
|
|
76
|
+
item.fn.call(fnThis, data);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.error(`Error in event listener for "${name}":`, err);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 跨页通信插件:通过 localStorage + storage 事件将当前实例的 emit 广播到其他同源页面。
|
|
86
|
+
* 支持节流、命名空间隔离。
|
|
87
|
+
*/
|
|
88
|
+
const MyEvent_CrossPagePlugin = (() => {
|
|
89
|
+
const INSTALLED = new WeakSet(); // 防止重复安装
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
/**
|
|
93
|
+
* 为指定 MyEvent 实例安装跨页插件。
|
|
94
|
+
* @param {MyEvent} bus - 事件总线实例
|
|
95
|
+
* @param {Options} [opts] - 配置项
|
|
96
|
+
*/
|
|
97
|
+
install(bus, opts = {}) {
|
|
98
|
+
if (INSTALLED.has(bus)) return;
|
|
99
|
+
INSTALLED.add(bus);
|
|
100
|
+
|
|
101
|
+
const ns = `___my-event-cross-page-${opts.namespace || "default"}___`;
|
|
102
|
+
const delay = opts.throttle || 16;
|
|
103
|
+
let last = 0;
|
|
104
|
+
|
|
105
|
+
// 1、重写 emit
|
|
106
|
+
const rawEmit = bus.emit;
|
|
107
|
+
bus.emit = function (name, data, fnThis) {
|
|
108
|
+
rawEmit.call(bus, name, data, fnThis); // 本地先执行
|
|
109
|
+
const now = Date.now();
|
|
110
|
+
if (now - last < delay) return;
|
|
111
|
+
last = now;
|
|
112
|
+
const key = ns + name;
|
|
113
|
+
try {
|
|
114
|
+
localStorage.setItem(key, JSON.stringify({ name, data, ts: now }));
|
|
115
|
+
localStorage.removeItem(key); // 触发 storage 事件
|
|
116
|
+
} catch (e) {}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// 2、监听其他页广播
|
|
120
|
+
function onStorageHandler(e) {
|
|
121
|
+
if (!e.key || !e.key.startsWith(ns)) return;
|
|
122
|
+
let payload;
|
|
123
|
+
try {
|
|
124
|
+
payload = JSON.parse(e.newValue || "{}");
|
|
125
|
+
} catch {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (!payload.ts || payload.ts <= last) return;
|
|
129
|
+
rawEmit.call(bus, e.key.slice(ns.length), payload.data); // 仅本地
|
|
130
|
+
}
|
|
131
|
+
addEventListener("storage", onStorageHandler);
|
|
132
|
+
|
|
133
|
+
// 3、保存卸载器
|
|
134
|
+
bus._uninstallCrossPage = () => {
|
|
135
|
+
removeEventListener("storage", onStorageHandler);
|
|
136
|
+
bus.emit = rawEmit;
|
|
137
|
+
INSTALLED.delete(bus);
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 卸载插件,恢复原始 emit 并停止监听。
|
|
143
|
+
* @param {MyEvent} bus - 事件总线实例
|
|
144
|
+
*/
|
|
145
|
+
uninstall(bus) {
|
|
146
|
+
if (typeof bus._uninstallCrossPage === "function") bus._uninstallCrossPage();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
149
|
})();
|
|
150
150
|
|
|
151
151
|
export { MyEvent, MyEvent_CrossPagePlugin };
|