在 Vue 3 的 Composition API 和 <script setup> 中,$on、$off、$once 等方法已被废弃,所以不能再使用 Vue 实例直接作为事件总线。
此文介绍的是使用mitt(轻量级第三方库)
mitt是什么
mitt
是一个轻量级的 JavaScript 事件总线(Event Bus)库,常用于在组件之间或模块之间进行 跨层级通信。它非常适合在 Vue、React 或其他前端框架中实现全局事件管理。
如何使用
准备工作
demo 继续使用笔记8中的 链接为demo
在views文件夹下 创建新的文件夹为eventbus
在eventbus文件夹下
创建文件Parent.vue
<template>
<div class="props-text">
<h1>Global Event Bus 全局事件总线</h1>
<h1>我是父组件</h1>
</div>
</template>
<script setup>
</script>
<style scoped>
.props-text {
width: 400px;
height: 400px;
background-color: burlywood;
}
</style>
添加路由
import {createRouter , createWebHistory} from 'vue-router'
const routes = [
{
path: '/',
name: 'index',
component: () => import('@/views/index.vue')
},
{
path: '/props',
name: 'props',
component: () => import('@/views/props/Parent.vue')
},
{
path: '/customevent',
name: 'customevent',
component: () => import('@/views/customevent/Parent.vue')
},
{
path: '/eventbus',
name: 'eventbus',
component: () => import('@/views/eventbus/Parent.vue')
},
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
app.vue中添加导航
<script setup>
</script>
<template>
<div class="com">
<h1>
各种Vue组件间通信/传值
</h1>
<div>
<h2 style="display: inline">演示:</h2>
<router-link to="/">index</router-link>
<router-link to="/props">props</router-link>
<router-link to="/customevent">custom event</router-link>
<router-link to="/eventbus">event bus</router-link>
</div>
<br>
<router-view></router-view>
</div>
</template>
<style scoped>
.com {
margin: 10px;
}
</style>
<style>
.box {
border: solid 1px #aaa;
margin: 5px;
padding: 5px;
}
</style>
分别创建子组件1 和 子组件2 用于子组件之间的数据传递
Child1.vue
<template>
<div class="son">
<h1>我是子组件1</h1>
<p>{{ msg }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const msg = ref('');
</script>
<style scoped>
.son {
width: 100px;
height: 100px;
background-color: red;
}
</style>
Child2.vue
<template>
<div class="son">
<h1>我是子组件2</h1>
<button @click="handler">点击我给子组件1传递</button>
</div>
</template>
<script setup>
const handler = () => {
}
</script>
<style scoped>
.son {
width: 100px;
height: 100px;
background-color: green;
}
</style>
父组件中 引用两个子组件
<template>
<div class="props-text">
<h1>全局事件总线Global Event Bus</h1>
<h1>我是父组件</h1>
<Child1></Child1>
<Child2></Child2>
</div>
</template>
<script setup>
import Child1 from './Child1.vue';
import Child2 from './Child2.vue';
</script>
<style scoped>
.props-text {
width: 400px;
height: 400px;
background-color: burlywood;
}
</style>
安装mitt
npm install mitt
基本使用mitt
在src文件夹 创新文件夹bus
bus 创建index.js
//引入mitt插件:mitt一个方法,方法执行会返回bus对象
import mitt from "mitt";
const $bus = mitt();
export default $bus;
开始组件中使用mitt
在子组件2中引用mitt
<template>
<div class="son">
<h1>我是子组件2</h1>
<button @click="handler">点击我给子组件1传递</button>
</div>
</template>
<script setup>
import $bus from '@/bus';
const handler = () => {
$bus.emit('son1', {data:'子组件2给子组件1传递的数据'})
}
</script>
<style scoped>
.son {
width: 100px;
height: 100px;
background-color: green;
}
</style>
子组件1中 使用
<template>
<div class="son">
<h1>我是子组件1</h1>
<p>{{ msg }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const msg = ref('');
import $bus from '../../bus';
console.log($bus)
import { onMounted } from 'vue'
//组件挂载完毕的时候,当前组件绑定一个事件,接受将来兄弟组件传递的数据
//什么是 onMounted?
//当组件被渲染并插入到 DOM 中后,onMounted 会被调用。此时你可以安全地访问 DOM 元素、发起网络请求、初始化第三方库等。
onMounted(() => {
console.log('组件已挂载')
// 可以在这里执行初始化操作,例如:
// - 获取数据
// - 操作 DOM
// - 初始化插件
//第一个参数:即为事件类型 第二个参数:即为事件回调
$bus.on('son1',(data) => {
console.log(data)
msg.value = data.data
})
})
</script>
<style scoped>
.son {
width: 100px;
height: 100px;
background-color: red;
}
</style>
控制台输出为
总结
支持的 API 方法
方法 | 说明 |
---|---|
on(type, handler) |
添加指定类型的事件监听器 |
off(type, handler) |
移除指定类型的事件监听器 |
emit(type, [event]) |
触发指定类型事件,并传递参数 |
all.clear() |
移除所有事件的所有监听器 |
注意事项
- 使用
mitt
时要小心内存泄漏问题,在组件卸载时记得移除监听器。 - 在 Vue 中,也可以考虑使用
provide/inject
或者Pinia/Vuex
状态管理替代mitt
,但mitt
更加简单灵活。 - 如果你在
<script setup>
中使用,可以用onBeforeUnmount
来清理监听器:
<script setup>
import $bus from '../../bus';
import { onMounted, onBeforeUnmount } from 'vue'
const handler = (data) => {
console.log('收到数据:', data)
}
onMounted(() => {
$bus.on('son1', handler)
})
onBeforeUnmount(() => {
$bus.off('son1', handler)
})
</script>
在 Vue 项目中的典型应用
适用于:
- 跨组件通信(非父子组件)
- 全局状态变化通知
- 插件间通信
- 解耦业务逻辑和 UI 层
特点 | 描述 |
---|---|
体积小 | 几 KB,无依赖 |
使用简单 | 提供 .on , .off , .emit |
可维护性强 | 适合中小型项目的事件通信 |
通用性高 | 可用于任何 JavaScript 项目 |