前言:在Vue升级到3.0版本后,prototype属性就被取消了,所以我们不能再使用Vue2中的Vue.prototype.$bus=new Vue()的方式来使用全局事件总线。在Vue3中,推荐使用mitt这一三方库来帮助我们实现全局事件总线。
Mitt是一个微型的 EventEmitter 库,在Vue3中,官方推荐使用它替代已经移除的EventBus。
npm install mitt --save
emit(name,data)
//触发事件,两个参数:name:触发的方法名,data:需要传递的参数
on(name,callback)
//绑定事件,两个参数:name:绑定的方法名,callback:触发后执行的回调函数
off(name)
//解绑事件,一个参数:name:需要解绑的方法名
在根目录下创建一个bus.ts
import mitt from "mitt";
const emitter = mitt()
export default emitter
<template>
<h1>
我是A组件
</h1>
<button @click="emitMitt">
点我控制B输出信息
</button>
</template>
<script lang='ts' setup>
import emitter from '@/util/bus'
const emitMitt = function(){
emitter.emit('printMessage','我是B组件,我被A组件触发了')
}
</script>
<template>
<h1>
我是B组件
</h1>
</template>
<script lang='ts' setup>
import { onMounted,onBeforeUnmount } from 'vue'
import emitter from '@/util/bus'
onMounted(()=>{
emitter.on('printMessage',(message)=>{
alert(message)
})
})
onBeforeUnmount(()=>{
emitter.off('printMessage')
})
</script>
注意:在事件的触发之前,要确定事件已经被绑定,否则是找不到触发事件的。
比如我们定义 EventBus.emit,然后马上进行路由跳转,然后在下一个组件中用,你会奇异的发现这个方法压根不会触发。也就是说mitt,emit触发第一次,on监听不到。
分析:因为emit 先于 on 执行了,VUE并没有储存监听事件,所以无法监听到数据。
我这里遇到的是在调用emit的时候子组件并没有创建,所以无法监听到数据,子组件创建之后,便可以监听到传递过来的数据。
我的解决方法是在调用emit的时候,使用 nextTick()方法
用法:将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。
nextTick(() => {
emitter.emit("setHomeChart", {
**, **
...
});
});
解决方案:
把emitter.on也放在setup里面,先监听,再发送消息,就可以监听到了。
emitter.on('setHomeChart', (message: any) => {
console.log(message, "message");
})
如果写在onMounted生命周期里面,在这里接收的时候发现,消息在发送之后,没办法接收到,使用全局的接收倒是可以接收到,但是单独接收这个不可以。这是因为现在的emitter.on是写在 onMounted生命周期里面,但是emitter.emit却是写在了setup里面,先发送了消息,才加的监听,那自然监听不到。
解决方案:
我们可以用"*"号监听到所有的事件。
onMounted(() => {
let srith: any;
emitter.on('*', (index, data) => {
if (index == "") {
if (srith !== index) {
srith = index;
console.log(data)
} else {
return
}
} else {
return
}
})
})
事件总线是全局的 也就是说 当你每次emit触发一次这条线就已经创建存在了 当整个程序在运行时他就会一直存在 每当你触发一次就会新建一条事件总线 也是为什么会触发多次函数的问题所在。如果需要移除,可在组件销毁前销毁当前事件总线。
onBeforeUnmount(()=>{
emitter.off("setHomeChart")
})