vue 3 中可用 mitt 实现轻量级跨组件通信,它仅200字节、不依赖 vue 实例、天然适配组合式 api,适用于简单消息传递且无需复杂状态管理的场景。

在 Vue 3 中,官方已移除 $on、$emit、$off 等实例方法,传统的事件总线(Event Bus)方式不再适用。但通过轻量级第三方库 mitt,依然可以简洁高效地实现非父子组件间的通信——它不依赖 Vue 实例,与组合式 API 天然契合。
为什么选 mitt 而不是 Vuex/Pinia?
mitt 是一个极简的事件发射/订阅工具(仅 200 字节),适用于以下场景:
- 跨层级、无直接关系的组件间传递简单消息(如:通知刷新列表、触发弹窗、同步开关状态)
- 不涉及复杂状态管理或持久化需求
- 希望避免引入大型状态库带来的学习和维护成本
安装与创建全局事件总线
在项目中安装 mitt:
npm install mitt
在 src/utils/bus.ts(或 src/bus.ts)中创建并导出一个 mitt 实例:
import mitt from 'mitt' const bus = mitt() export default bus
⚠️ 注意:必须只创建一个实例并复用,不能在每个组件里 new 一个新的 mitt,否则订阅和发布将无法匹配。
在组件中使用:emit 和 on
以两个无关组件为例:Form.vue 提交后通知 List.vue 刷新数据。
发送事件(Form.vue):
import { defineComponent } from 'vue'
import bus from '@/utils/bus'
export default defineComponent({
setup() {
const handleSubmit = () => {
// 模拟提交
bus.emit('refresh-list', { from: 'form' })
}
return { handleSubmit }
}
})
监听事件(List.vue):
import { defineComponent, onUnmounted } from 'vue'
import bus from '@/utils/bus'
export default defineComponent({
setup() {
const handleRefresh = (payload: any) => {
console.log('收到刷新请求', payload)
// 执行刷新逻辑,如 refetch()
}
// 订阅事件
bus.on('refresh-list', handleRefresh)
// 组件卸载时务必取消监听,防止内存泄漏
onUnmounted(() => {
bus.off('refresh-list', handleRefresh)
})
return {}
}
})
✅ 关键点:
- 使用
bus.on()订阅,bus.emit()发布 - 必须在
onUnmounted中调用bus.off()清理监听器(尤其在 setup 中定义的回调) - 若使用箭头函数内联监听(如
bus.on('x', () => {...})),则无法在卸载时精准off,应避免
进阶:封装成 Composable 函数(推荐)
为提升复用性和可维护性,可封装一个 useBus 组合式函数:
// composables/useBus.ts
import { onUnmounted } from 'vue'
import bus from '@/utils/bus'
export function useBus<t extends string>(event: T) {
const on = (fn: (payload: any) => void) => {
bus.on(event, fn)
onUnmounted(() => bus.off(event, fn))
}
const emit = (payload?: any) => {
bus.emit(event, payload)
}
return {
on,
emit
}
}</t>
在组件中使用更简洁:
// List.vue
import { defineComponent } from 'vue'
import { useBus } from '@/composables/useBus'
export default defineComponent({
setup() {
const { on } = useBus('refresh-list')
on((payload) => {
console.log('刷新列表', payload)
})
return {}
}
})
这种写法自动处理了生命周期清理,语义清晰,适合中大型项目统一管理事件通信。
mitt 不是银弹,但它在 Vue 3 的轻量通信场景中足够可靠、透明且易控。只要注意事件命名规范(建议用 kebab-case 或命名空间前缀,如 'user:updated')、及时解绑、避免过度使用,就能成为父子通信之外的有力补充。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










