Vue3中推荐使用mitt实现轻量级事件总线,因其替代了被废弃的new Vue()全局事件总线,解决了setup中无this问题,且比Vuex/Pinia更简洁,支持TypeScript类型安全,并可通过自定义Hook自动清理监听器。

在 Vue3 中,mitt 是实现轻量级事件总线(消息总线)的主流方案,它替代了 Vue2 中的 Vue.prototype.$bus 或全局事件总线模式,解决了组合式 API 下缺乏 this 上下文、无法直接挂载实例属性的问题。
为什么 Vue3 不再推荐自建 EventBus?
Vue3 废除了 new Vue() 构造函数,且 setup() 中没有 this,导致传统基于 Vue 实例的事件总线无法直接复用。手动用 emits: [] 或 defineEmits 只适用于父子通信;Vuex/Pinia 适合状态管理,但对简单跨组件通知(如“刷新列表”“关闭弹窗”)显得过重。mitt 提供了一个极简、无依赖、类型安全(配合 TypeScript)的发布-订阅工具。
安装与基础用法
通过 npm 安装:
npm install mitt
创建一个独立的 bus 实例(推荐放在 src/utils/bus.js 或 src/bus/index.js):
import mitt from 'mitt'<br>const bus = mitt()<br>export default bus
在任意组件中使用:
审查 Vue 管理后台的变更请求(Vue 2 + Element UI,Vue 3 + Element Plus)。重点关注最小化变更实现、上线风险检查以及回归检查清单生成。
-
发送消息:调用
bus.emit('event-name', payload),payload 可以是任意类型(对象、字符串、布尔值等) -
监听消息:调用
bus.on('event-name', handler),handler 接收 payload 参数 -
移除监听:调用
bus.off('event-name', handler)(避免内存泄漏,尤其在onUnmounted中清理)
在 setup() 中正确使用并自动清理
由于 mitt 的监听器是手动注册的,必须确保组件卸载时取消订阅。推荐写法如下:
import { onMounted, onUnmounted } from 'vue'<br>import bus from '@/utils/bus'<br><br>export default {<br> setup() {<br> const handleRefresh = (data) => {<br> console.log('收到刷新请求', data)<br> // 执行刷新逻辑<br> }<br><br> onMounted(() => {<br> bus.on('refresh-list', handleRefresh)<br> })<br><br> onUnmounted(() => {<br> bus.off('refresh-list', handleRefresh)<br> })<br><br> const triggerRefresh = () => {<br> bus.emit('refresh-list', { from: 'button-click' })<br> }<br><br> return { triggerRefresh }<br> }<br>}
进阶技巧:类型提示 + 自动清理 Hook
为提升可维护性,可封装一个自定义 Hook:
// composables/useBus.js<br>import { onUnmounted } from 'vue'<br>import mitt from 'mitt'<br><br>const bus = mitt()<br><br>export function useBus() {<br> const on = (event, handler) => {<br> bus.on(event, handler)<br> onUnmounted(() => bus.off(event, handler))<br> }<br><br> const emit = (event, ...args) => bus.emit(event, ...args)<br><br> return { on, emit }<br>}
在组件中直接解构使用,无需手动 off:
import { useBus } from '@/composables/useBus'<br><br>export default {<br> setup() {<br> const { on, emit } = useBus()<br><br> on('user-login', (user) => {<br> console.log('用户已登录:', user)<br> })<br><br> const login = () => emit('user-login', { id: 123, name: 'Alice' })<br><br> return { login }<br> }<br>}
注意事项与替代建议
- mitt 不支持通配符或事件继承,仅支持精确匹配事件名
- 不适用于高频、大量数据通信场景(考虑用 provide/inject 或 Pinia)
- 若项目已用 Pinia,优先通过 store 的 actions + $subscribe 实现跨组件响应,更利于调试和状态追踪
- 生产环境建议给事件名加命名空间前缀(如
ui:close-modal、api:fetch-failed),避免冲突
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









