Vue 3 根实例不支持自定义事件监听与派发,官方推荐使用 mitt 实现跨层级事件通信;mitt 轻量无依赖,提供 emit/on/off 方法,替代 Vue 2 EventBus。

Vue 3 的根实例(即 createApp(App) 创建的应用实例)本身不支持直接监听或派发自定义事件,它没有类似 Vue 2 中的 $on/$off/$once 方法。所谓“在根实例上跨层级派发自定义事件”,实际是指让任意组件都能触发和响应同一套全局事件机制,而不是把事件挂到根实例上。
用 mitt 实现真正的跨层级事件通信
这是 Vue 3 官方推荐、社区最主流的替代方案。mitt 是一个轻量、无依赖的事件总线库,完全取代了 Vue 2 的 EventBus。
- 安装:
npm install mitt - 创建事件总线(如
eventBus.js):import mitt from 'mitt'<br>export const eventBus = mitt()
- 在任意组件中使用:
→ 触发事件:eventBus.emit('user-login', { id: 123 })
→ 监听事件:eventBus.on('user-login', handler)
→ 移除监听(建议在onUnmounted中调用):eventBus.off('user-login', handler)
为什么不能直接在根实例上绑定事件?
Vue 3 已彻底移除实例上的事件 API($on/$off/$once),只保留 $emit 用于父子间声明式事件传递。根实例的 props(如 createApp(App, { onExpand() { ... } }))仅支持静态声明的、预定义的事件回调,无法动态注册/解绑,也不适用于组件间通用通信。
从零开始编排 SpringBoot+Vue 全栈项目工作流,适用于新建全栈项目或完整脚手架请求,触发后依次调用 product‑spec‑builder(需求调研)等模块。
provide/inject 不适合替代事件总线
虽然 provide/inject 可跨多层传递响应式数据或函数,但它不是事件机制:
→ 它适合共享状态或方法,但无法实现“广播+订阅”模式;
→ 没有事件的解耦性,inject 方需主动调用函数,无法被动响应;
→ 不具备事件去重、once、off 等能力,不适合松耦合的跨组件通知场景。
立即学习“前端免费学习笔记(深入)”;
其他不推荐的方式
- 滥用 $parent 或 $root:破坏封装性,不可靠且难以维护;
- 用 Pinia/Vuex 存储状态 + watch 响应变化:可行但过度设计,事件本质是“动作通知”,不是状态同步;
- 全局挂载 mitt 到 app.config.globalProperties:虽能用,但违背 Composition API 设计理念,增加隐式依赖,不推荐。

















