第三方插件 mitt 实现跨组件通信
什么是 mitt?
mitt
是一个轻量级的事件发射器/事件总线,它只有 200 bytes 大小,不依赖于任何框架,可以方便地集成到 Vue 应用中。mitt
提供了一个简单的 API 来发布事件和订阅事件,非常适合用来替代 Vue 2 中的 EventBus
模式。
优点
-
轻量级:
mitt
的体积非常小,压缩后只有约 200 字节,对项目性能影响极小。 -
简单易用: API 设计简洁,易于理解和使用。主要提供了
on
,off
,emit
和once
四个方法。 -
无依赖: mitt 不依赖任何外部库或框架,可以在任何 JavaScript 环境下使用,包括浏览器和 Node.js。
-
跨平台: 可以在多种环境中使用,包括前端 Web 应用、Node.js 后端服务等。
-
灵活性: 可以方便地在组件间传递任意类型的数据,包括对象、数组等复杂结构。
-
事件管理: 支持一次性监听
once
,可以更灵活地管理事件监听器。
缺点
-
命名冲突: 如果多个组件使用相同的事件名称,可能会导致命名冲突。尤其是在大型项目中,这种风险更高。
-
难以调试: 事件总线模式下的错误定位和调试相对困难,因为事件的触发和处理发生在不同的组件中。
-
缺乏状态管理:
mitt
本质上只是一个事件总线,不提供状态管理功能。对于复杂的状态管理需求,可能需要结合其他状态管理库(如 Vuex)。 -
全局污染: 如果不当使用全局事件总线,可能会导致全局污染问题,特别是在多模块或多页面应用中。
-
过度使用: 过度依赖事件总线可能导致代码耦合度增加,降低代码的可读性和可维护性。
-
性能问题: 大量事件监听器可能导致性能问题,特别是在高频率事件触发的情况下。虽然
mitt
本身很轻量,但如果事件处理逻辑复杂,仍然会影响性能。
\8
如何使用 mitt 实现组件通信
1. 安装 mitt
npm install mitt
# 或者
yarn add mitt
2. 创建事件总线
创建一个全局的 mitt 实例,通常我们会创建一个独立的文件来管理这个事件总线,这样可以在整个应用中共享这个事件总线。
eventBus.js
// eventBus.js
import mitt from 'mitt';
// 创建一个 mitt 实例
const eventBus = mitt();
export default eventBus;
3. 在组件中使用事件总线
-
发布事件:在一个组件中触发事件。
-
订阅事件:在另一个组件中监听事件。
使用
引入 mitt:
import mitt from 'mitt';
const emitter = mitt();
定义事件监听器:
emitter.on('eventName', (data) => {
console.log('Received data:', data);
});
触发事件:
emitter.emit('eventName', {
key: 'value' });
取消监听:
emitter.off('eventName', listener);
一次性监听:
// 仅监听一次名为 'eventName' 的事件
emitter.once('eventName', (data) => {
console.log(data);
});
在 Vue 应用中,你可以创建一个全局的 mitt 实例,并在需要通信的组件中使用这个实例来触发和监听事件。这种方式特别适用于那些没有父子关系或者跨越多个层级的组件间的通信。
在 main.js 或类似入口文件中设置全局事件总线:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import mitt from 'mitt';
// 创建一个 mitt 实例
const emitter = mitt();
// 将 mitt 实例添加到全局属性
Vue.prototype.$emitter = emitter;
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
在 Vue 组件中,可以通过 this.$bus 访问全局事件总线:
export default {
mounted() {
this.$emitter.on('eventName', (data) => {
console.log(data);
});
},
beforeUnmount() {
this.$emitter.off('eventName');
},
methods: {
triggerEvent() {
this.$emitter.emit('eventName', 'Hello from component!');
}
}
}
组件通信
c组件
<template>
<div class="son">
<h2>C组件</h2>
<el-button type="primary" @click="sendMessage">发送消息</el-button>
</div>
</template>
<script>
export default {
name: 'CCC',
methods: {
sendMessage() {
this.$emitter.emit('sedMsg', "This is some shared data")
}
}
}
</script>
b组件
<template>
<div class="parent">
<h2>B组件</h2>
<div>{
{
message }}</div>
</div>
</template>
<script>
export default {
name: 'BBB',
data() {
return {
message: ""
}
},
created() {
this.getMassage();
},
methods: {
// 接受参数
getMassage() {
this.$emitter.on('sedMsg', (msg) => {
this.message = msg;
})
}
}
}
</script>
a组件
<template>
<div class="grandpa">
<h2>A组件</h2>
<div>{
{
msg }}</div>
</div>
</template>
<script>
export default {
name: 'AAA',
data() {
return {
msg: ""
}
},
created() {
this.getMassage()
},
methods: {
// 接受参数
getMassage() {
this.$emitter.on('sedMsg', (msg) => {
this.msg = msg
})
},
}
}
</script>
上述示例中:
-
ccc.vue 组件通过
this.$emitter.emit
方法传递参数。 -
bcc.vue 和 bcc.vue 组件通过
this.$emitter.on
接收了参数,并在模板中使用。
总结
-
创建全局事件总线:在应用入口文件中创建一个 mitt 实例,并将其挂载到全局属性上。
-
注册事件监听器:在接收数据的组件中注册事件监听器。
-
触发事件并传递参数:在发送数据的组件中触发事件,并传递参数。
-
事件处理:监听器接收到事件并处理参数。
这种方式使得组件之间能够通过事件总线进行解耦通信,提高了组件的可维护性和灵活性。