vue 3 中 reactive 不直接提供 eventbus 能力,需结合 watch 等实现;官方推荐优先使用 props/emits、provide/inject 或 pinia;reactive 适合管理状态,不适合替代事件分发逻辑。

在 Vue 3 中,reactive 本身不直接提供事件总线(EventBus)能力,但它可以和 emits、watch 或自定义逻辑结合,构建一个轻量、响应式的全局通信机制。不过要注意:官方推荐优先使用 props/emits、provide/inject 或状态管理(如 Pinia),EventBus 属于过渡或特殊场景方案。
用 reactive + watch 模拟 EventBus
核心思路是创建一个响应式对象,把事件回调存为函数数组,再通过 watch 监听“触发动作”,执行对应回调。
示例实现:
import { reactive, watch } from 'vue'
const eventBus = reactive({
events: {}
})
// 触发事件(写入)
function emit(event, payload) {
eventBus.events[event] = { payload, timestamp: Date.now() }
}
// 订阅事件(监听)
function on(event, callback) {
if (!eventBus.events[event]) {
eventBus.events[event] = { payload: null, timestamp: 0 }
}
// 利用 watch 监听特定事件键的变化
watch(
() => eventBus.events[event],
(newVal) => {
if (newVal && newVal.payload !== undefined) {
callback(newVal.payload)
}
},
{ immediate: false }
)
}
// 取消订阅(需手动管理,此处简化)
function off(event) {
delete eventBus.events[event]
}
用法:
- 在组件 A 中:
emit('user-login', { id: 123 }) - 在组件 B 中:
on('user-login', (data) => console.log(data))
更实用的封装:基于 ref 的简易 EventBus 类
用 ref 存储回调列表,配合 reactive 管理事件状态,更易维护和类型提示:
import { ref, onUnmounted } from 'vue'
class SimpleEventBus {
constructor() {
this.callbacks = new Map()
}
on(event, callback) {
if (!this.callbacks.has(event)) {
this.callbacks.set(event, [])
}
const listeners = this.callbacks.get(event)
listeners.push(callback)
// 自动清理(配合组件生命周期)
onUnmounted(() => {
const idx = listeners.indexOf(callback)
if (idx > -1) listeners.splice(idx, 1)
})
}
emit(event, payload) {
const listeners = this.callbacks.get(event)
if (listeners) {
listeners.forEach(cb => cb(payload))
}
}
off(event, callback) {
const listeners = this.callbacks.get(event)
if (listeners) {
const idx = listeners.indexOf(callback)
if (idx > -1) listeners.splice(idx, 1)
}
}
}
export const eventBus = new SimpleEventBus()
这个版本不依赖 reactive 做响应式驱动,但更贴近实际开发习惯,也兼容组合式 API 的生命周期控制。
为什么不直接用 reactive 包裹 callbacks?
因为 reactive 对 Map/Set/Function 等类型有局限 —— 它无法自动追踪 Map 的 set 或 delete 操作,也无法响应函数数组的 push 后的 length 变化。所以直接 reactive({ callbacks: [] }) 并监听它,往往不会按预期触发更新。
换句话说:reactive 适合管理状态数据,不适合替代事件分发逻辑本身。把它当作“触发信号的载体”可以,但别指望它自动帮你派发事件。
替代建议:优先考虑 provide / inject
对于跨层级通信,比 EventBus 更 Vue 3 原生的方式是:
- 父组件用
provide({ emit: (e, p) => {...} }) - 子组件用
inject拿到并调用 - 配合
computed或ref实现响应式数据共享
这样既保持响应性,又避免全局污染和内存泄漏风险。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











