@fyh-mengxiang/vue3-event-bus 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,252 @@
1
+ # vue3-event-bus
2
+
3
+ 一个简单轻量的Vue 3事件总线库,支持Composition API和Option API。
4
+
5
+ ## 特性
6
+
7
+ - ✅ 支持Vue 3的Composition API和Option API
8
+ - ✅ 提供单例模式,全局共享
9
+ - ✅ 支持事件订阅、发布、取消订阅
10
+ - ✅ 支持一次性事件
11
+ - ✅ 提供事件管理功能
12
+ - ✅ 轻量无依赖
13
+ - ✅ 兼容TypeScript
14
+
15
+ ## 安装
16
+
17
+ ### NPM安装
18
+
19
+ ```bash
20
+ npm install vue3-event-bus
21
+ ```
22
+
23
+ ### 本地开发安装
24
+
25
+ ```bash
26
+ # 在项目根目录执行
27
+ npm install ./vue3-event-bus
28
+ ```
29
+
30
+ ## 使用
31
+
32
+ ### 1. 全局注册(推荐)
33
+
34
+ 在`main.js`中使用`Vue.use()`注册:
35
+
36
+ ```javascript
37
+ import { createApp } from 'vue'
38
+ import App from './App.vue'
39
+ import EventBus from 'vue3-event-bus'
40
+
41
+ const app = createApp(App)
42
+ app.use(EventBus, { debug: true }) // debug选项可选
43
+ app.mount('#app')
44
+ ```
45
+
46
+ ### 2. 在组件中使用
47
+
48
+ #### Option API
49
+
50
+ ```vue
51
+ <template>
52
+ <div>
53
+ <button @click="sendEvent">发送事件</button>
54
+ </div>
55
+ </template>
56
+
57
+ <script>
58
+ export default {
59
+ methods: {
60
+ sendEvent() {
61
+ // 发送事件
62
+ this.$eventBus.emit('test-event', 'Hello EventBus')
63
+ },
64
+ },
65
+ mounted() {
66
+ // 订阅事件
67
+ this.$eventBus.on('test-event', this.handleEvent)
68
+ },
69
+ beforeUnmount() {
70
+ // 取消订阅
71
+ this.$eventBus.off('test-event', this.handleEvent)
72
+ },
73
+ }
74
+ </script>
75
+ ```
76
+
77
+ #### Composition API
78
+
79
+ ```vue
80
+ <template>
81
+ <div>
82
+ <button @click="sendEvent">发送事件</button>
83
+ </div>
84
+ </template>
85
+
86
+ <script setup>
87
+ import { inject, onMounted, onUnmounted } from 'vue'
88
+
89
+ // 通过inject获取eventBus实例
90
+ const eventBus = inject('eventBus')
91
+
92
+ // 事件处理函数
93
+ const handleEvent = (data) => {
94
+ console.log('收到事件:', data)
95
+ }
96
+
97
+ // 发送事件
98
+ const sendEvent = () => {
99
+ eventBus.emit('test-event', 'Hello EventBus')
100
+ }
101
+
102
+ onMounted(() => {
103
+ // 订阅事件
104
+ eventBus.on('test-event', handleEvent)
105
+ })
106
+
107
+ onUnmounted(() => {
108
+ // 取消订阅
109
+ eventBus.off('test-event', handleEvent)
110
+ })
111
+ </script>
112
+ ```
113
+
114
+ ### 3. 直接使用单例实例
115
+
116
+ ```javascript
117
+ import { eventBus } from 'vue3-event-bus'
118
+
119
+ eventBus.on('test-event', (data) => {
120
+ console.log('收到事件:', data)
121
+ })
122
+
123
+ eventBus.emit('test-event', 'Hello EventBus')
124
+ ```
125
+
126
+ ## API
127
+
128
+ ### `on(eventName, callback, options?)`
129
+
130
+ 订阅事件
131
+
132
+ - `eventName`: 事件名称(字符串)
133
+ - `callback`: 回调函数
134
+ - `options`: 可选配置
135
+ - `once`: 是否只触发一次(布尔值,默认为false)
136
+ - 返回值: 取消订阅的函数
137
+
138
+ ### `once(eventName, callback)`
139
+
140
+ 订阅一次事件,触发后自动取消订阅
141
+
142
+ - `eventName`: 事件名称(字符串)
143
+ - `callback`: 回调函数
144
+ - 返回值: 取消订阅的函数
145
+
146
+ ### `off(eventName, callback?)`
147
+
148
+ 取消订阅事件
149
+
150
+ - `eventName`: 事件名称(字符串)
151
+ - `callback`: 可选,指定要取消的回调函数。如果不提供,则取消该事件的所有订阅
152
+
153
+ ### `emit(eventName, ...args)`
154
+
155
+ 发布/触发事件
156
+
157
+ - `eventName`: 事件名称(字符串)
158
+ - `...args`: 传递给回调函数的参数
159
+
160
+ ### `listenerCount(eventName)`
161
+
162
+ 获取指定事件的订阅者数量
163
+
164
+ - `eventName`: 事件名称(字符串)
165
+ - 返回值: 订阅者数量(数字)
166
+
167
+ ### `getEvents()`
168
+
169
+ 获取所有订阅的事件名称
170
+
171
+ - 返回值: 事件名称数组
172
+
173
+ ### `clear()`
174
+
175
+ 清除所有事件订阅
176
+
177
+ ## 示例
178
+
179
+ ### 基本使用
180
+
181
+ ```javascript
182
+ // 订阅事件
183
+ const unsubscribe = eventBus.on('test-event', (data) => {
184
+ console.log('收到数据:', data)
185
+ })
186
+
187
+ // 发送事件
188
+ eventBus.emit('test-event', { message: 'Hello' })
189
+
190
+ // 取消订阅
191
+ unsubscribe() // 或 eventBus.off('test-event')
192
+ ```
193
+
194
+ ### 一次性事件
195
+
196
+ ```javascript
197
+ eventBus.once('once-event', (data) => {
198
+ console.log('这个事件只会触发一次:', data)
199
+ })
200
+
201
+ eventBus.emit('once-event', '第一次触发') // 会执行
202
+
203
+ eventBus.emit('once-event', '第二次触发') // 不会执行
204
+ ```
205
+
206
+ ### 事件管理
207
+
208
+ ```javascript
209
+ // 获取事件数量
210
+ const count = eventBus.listenerCount('test-event')
211
+ console.log('订阅者数量:', count)
212
+
213
+ // 获取所有事件名称
214
+ const events = eventBus.getEvents()
215
+ console.log('所有事件:', events)
216
+
217
+ // 清除所有订阅
218
+ eventBus.clear()
219
+ ```
220
+
221
+ ## 注意事项
222
+
223
+ 1. **组件卸载时取消订阅**:为避免内存泄漏,组件卸载前应取消订阅相关事件
224
+ 2. **事件名称规范**:建议使用命名空间(如`user:login`)避免事件名称冲突
225
+ 3. **回调函数作用域**:注意回调函数中的`this`指向
226
+ 4. **不要滥用EventBus**:对于复杂的状态管理,建议使用Vuex或Pinia
227
+
228
+ ## 浏览器支持
229
+
230
+ - Chrome (最新)
231
+ - Firefox (最新)
232
+ - Safari (最新)
233
+ - Edge (最新)
234
+
235
+ 解决Bug
236
+ 一.如何解决页面执行时先emit后on导致事件监听失效的问题
237
+
238
+ ## 1. 核心改进
239
+
240
+ - 添加了事件缓存机制 :当事件发布时如果没有订阅者,事件会被缓存起来
241
+ - 订阅时自动触发缓存事件 :当组件订阅事件时,会自动触发所有缓存的该事件
242
+ - 配置化设计 :支持通过选项控制缓存行为,如是否启用缓存、最大缓存数量等
243
+ - 完整的缓存管理 :提供了清除缓存、查看缓存数量等API
244
+ // main.js中配置
245
+ app.use(EventBus, {
246
+ debug: true, // debug模式
247
+ eventBusOptions: {
248
+ enableCache: true, // 启用事件缓存
249
+ maxCacheSize: 10, // 每个事件最大缓存10条,默认缓存10条
250
+ clearCacheAfterSubscribe: true // 订阅后自动清除缓存
251
+ }
252
+ })
package/index.js ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Vue 3 EventBus 主入口文件
3
+ * 支持 Vue.use() 安装方式
4
+ */
5
+
6
+ import EventBus from './src/EventBus.js'
7
+
8
+ // 创建单例实例,支持通过 install 方法传递选项
9
+ let eventBusInstance = new EventBus()
10
+
11
+ /**
12
+ * Vue 3 插件安装函数
13
+ * @param {import('vue').App} app - Vue 应用实例
14
+ * @param {Object} options - 插件选项
15
+ */
16
+ function install(app, options = {}) {
17
+ // 如果提供了 EventBus 配置,重新创建实例
18
+ if (options.eventBusOptions) {
19
+ eventBusInstance = new EventBus(options.eventBusOptions)
20
+ }
21
+
22
+ // 全局注入 eventBus,支持 Composition API
23
+ app.provide('eventBus', eventBusInstance)
24
+
25
+ // 添加到全局属性,支持 Option API
26
+ app.config.globalProperties.$eventBus = eventBusInstance
27
+
28
+ // 可选:在控制台输出安装信息
29
+ if (options.debug) {
30
+ console.log('Vue 3 EventBus 已安装', { options })
31
+ }
32
+ }
33
+
34
+ // 导出插件
35
+ export default {
36
+ install,
37
+ }
38
+
39
+ // 导出单例实例,支持直接使用
40
+ export const eventBus = eventBusInstance
41
+
42
+ // 导出类,支持自定义实例
43
+ export { EventBus }
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@fyh-mengxiang/vue3-event-bus",
3
+ "version": "1.0.0",
4
+ "description": "A simple and lightweight EventBus for Vue 3, supporting both Composition API and Option API",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "build": "echo \"Build completed\"",
10
+ "prepare": "npm run build"
11
+ },
12
+ "keywords": [
13
+ "vue3",
14
+ "eventbus",
15
+ "vue-event-bus",
16
+ "vue3-event-bus",
17
+ "event-emitter"
18
+ ],
19
+ "author": "",
20
+ "license": "MIT",
21
+ "peerDependencies": {
22
+ "vue": "^3.0.0"
23
+ },
24
+ "devDependencies": {
25
+ "vue": "^3.0.0"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/fyh-mengxiang/vue3-plugins.git"
30
+ },
31
+ "bugs": {
32
+ "url": "https://github.com/fyh-mengxiang/vue3-plugins/issues"
33
+ },
34
+ "homepage": "https://github.com/fyh-mengxiang/vue3-plugins#readme",
35
+ "engines": {
36
+ "node": ">=14.0.0"
37
+ }
38
+ }
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Vue 3 EventBus 核心实现
3
+ * 支持事件订阅、发布、取消订阅等功能
4
+ * 支持事件缓存,解决先执行顺序先emit后on的问题
5
+ */
6
+
7
+ class EventBus {
8
+ constructor(options = {}) {
9
+ // 存储事件订阅者
10
+ this.events = {}
11
+ // 存储已发布但未被订阅的事件(事件缓存)
12
+ this.eventCache = {}
13
+ // 配置选项
14
+ this.options = {
15
+ // 是否启用事件缓存
16
+ enableCache: options.enableCache !== false,
17
+ // 每个事件的最大缓存数量,0表示不限制
18
+ maxCacheSize: options.maxCacheSize || 10,
19
+ // 是否在订阅后自动清除缓存
20
+ clearCacheAfterSubscribe: options.clearCacheAfterSubscribe !== false,
21
+ ...options,
22
+ }
23
+ }
24
+
25
+ /**
26
+ * 订阅事件
27
+ * @param {string} eventName - 事件名称
28
+ * @param {Function} callback - 回调函数
29
+ * @param {Object} options - 选项配置
30
+ * @param {boolean} options.once - 是否只触发一次
31
+ * @returns {Function} - 取消订阅的函数
32
+ */
33
+ on(eventName, callback, options = {}) {
34
+ if (typeof callback !== 'function') {
35
+ throw new TypeError('回调函数必须是函数类型')
36
+ }
37
+
38
+ if (!this.events[eventName]) {
39
+ this.events[eventName] = []
40
+ }
41
+
42
+ // 创建订阅者对象
43
+ const subscriber = {
44
+ callback,
45
+ once: !!options.once,
46
+ }
47
+
48
+ this.events[eventName].push(subscriber)
49
+
50
+ // 检查是否有缓存的事件,如果有则触发
51
+ if (this.options.enableCache && this.eventCache[eventName]) {
52
+ // 复制缓存列表,防止在处理过程中修改
53
+ const cachedEvents = [...this.eventCache[eventName]]
54
+
55
+ // 触发所有缓存的事件
56
+ cachedEvents.forEach((cached) => {
57
+ try {
58
+ callback(...cached.args)
59
+ } catch (error) {
60
+ console.error(`EventBus 缓存事件 "${eventName}" 回调执行出错:`, error)
61
+ }
62
+
63
+ // 如果是一次性事件,触发后移除订阅
64
+ if (subscriber.once) {
65
+ this.off(eventName, callback)
66
+ }
67
+ })
68
+
69
+ // 根据配置清除缓存
70
+ if (this.options.clearCacheAfterSubscribe) {
71
+ delete this.eventCache[eventName]
72
+ }
73
+ }
74
+
75
+ // 返回取消订阅的函数,方便在组件中使用
76
+ return () => this.off(eventName, callback)
77
+ }
78
+
79
+ /**
80
+ * 订阅一次事件
81
+ * @param {string} eventName - 事件名称
82
+ * @param {Function} callback - 回调函数
83
+ * @returns {Function} - 取消订阅的函数
84
+ */
85
+ once(eventName, callback) {
86
+ return this.on(eventName, callback, { once: true })
87
+ }
88
+
89
+ /**
90
+ * 取消订阅事件
91
+ * @param {string} eventName - 事件名称
92
+ * @param {Function} [callback] - 可选的回调函数,不提供则取消该事件的所有订阅
93
+ */
94
+ off(eventName, callback) {
95
+ if (!this.events[eventName]) {
96
+ return
97
+ }
98
+
99
+ if (!callback) {
100
+ // 取消该事件的所有订阅
101
+ delete this.events[eventName]
102
+ return
103
+ }
104
+
105
+ // 取消指定的订阅
106
+ this.events[eventName] = this.events[eventName].filter(
107
+ (listener) => listener.callback !== callback,
108
+ )
109
+
110
+ // 如果没有订阅者了,清理该事件
111
+ if (this.events[eventName].length === 0) {
112
+ delete this.events[eventName]
113
+ }
114
+ }
115
+
116
+ /**
117
+ * 发布/触发事件
118
+ * @param {string} eventName - 事件名称
119
+ * @param {...any} args - 传递给回调函数的参数
120
+ */
121
+ emit(eventName, ...args) {
122
+ let hasListeners = false
123
+
124
+ // 如果有订阅者,直接触发
125
+ if (this.events[eventName]) {
126
+ hasListeners = true
127
+ // 复制一份订阅者列表,防止在触发过程中修改订阅列表
128
+ const listeners = [...this.events[eventName]]
129
+
130
+ listeners.forEach((listener) => {
131
+ try {
132
+ listener.callback(...args)
133
+ } catch (error) {
134
+ console.error(`EventBus 事件 "${eventName}" 回调执行出错:`, error)
135
+ }
136
+
137
+ // 如果是一次性事件,触发后自动取消订阅
138
+ if (listener.once) {
139
+ this.off(eventName, listener.callback)
140
+ }
141
+ })
142
+ }
143
+
144
+ // 如果没有订阅者且启用了事件缓存,将事件缓存起来
145
+ if (!hasListeners && this.options.enableCache) {
146
+ // 初始化缓存数组
147
+ if (!this.eventCache[eventName]) {
148
+ this.eventCache[eventName] = []
149
+ }
150
+
151
+ // 添加到缓存
152
+ this.eventCache[eventName].push({
153
+ args: [...args],
154
+ timestamp: Date.now(),
155
+ })
156
+
157
+ // 限制缓存数量
158
+ if (this.options.maxCacheSize > 0) {
159
+ const overflow = this.eventCache[eventName].length - this.options.maxCacheSize
160
+ if (overflow > 0) {
161
+ // 移除最早的缓存
162
+ this.eventCache[eventName].splice(0, overflow)
163
+ }
164
+ }
165
+ }
166
+ }
167
+
168
+ /**
169
+ * 获取指定事件的订阅者数量
170
+ * @param {string} eventName - 事件名称
171
+ * @returns {number} - 订阅者数量
172
+ */
173
+ listenerCount(eventName) {
174
+ return this.events[eventName] ? this.events[eventName].length : 0
175
+ }
176
+
177
+ /**
178
+ * 获取指定事件的缓存数量
179
+ * @param {string} eventName - 事件名称
180
+ * @returns {number} - 缓存事件数量
181
+ */
182
+ cacheCount(eventName) {
183
+ return this.eventCache[eventName] ? this.eventCache[eventName].length : 0
184
+ }
185
+
186
+ /**
187
+ * 清除所有事件订阅
188
+ * @param {boolean} clearCache - 是否同时清除事件缓存
189
+ */
190
+ clear(clearCache = true) {
191
+ this.events = {}
192
+ if (clearCache) {
193
+ this.clearCache()
194
+ }
195
+ }
196
+
197
+ /**
198
+ * 清除事件缓存
199
+ * @param {string} [eventName] - 可选,指定要清除的事件缓存,不提供则清除所有
200
+ */
201
+ clearCache(eventName) {
202
+ if (eventName) {
203
+ delete this.eventCache[eventName]
204
+ } else {
205
+ this.eventCache = {}
206
+ }
207
+ }
208
+
209
+ /**
210
+ * 获取所有订阅的事件名称
211
+ * @returns {string[]} - 事件名称数组
212
+ */
213
+ getEvents() {
214
+ return Object.keys(this.events)
215
+ }
216
+
217
+ /**
218
+ * 获取所有缓存的事件名称
219
+ * @returns {string[]} - 事件名称数组
220
+ */
221
+ getCachedEvents() {
222
+ return Object.keys(this.eventCache)
223
+ }
224
+
225
+ /**
226
+ * 获取事件缓存配置
227
+ * @returns {Object} - 配置选项
228
+ */
229
+ getOptions() {
230
+ return { ...this.options }
231
+ }
232
+
233
+ /**
234
+ * 更新事件缓存配置
235
+ * @param {Object} newOptions - 新的配置选项
236
+ */
237
+ updateOptions(newOptions) {
238
+ this.options = { ...this.options, ...newOptions }
239
+ }
240
+ }
241
+
242
+ export default EventBus