解决vue3 mitt路由跳转后 on事件获取不到值的奇葩问题解决

前言:在Vue升级到3.0版本后,prototype属性就被取消了,所以我们不能再使用Vue2中的Vue.prototype.$bus=new Vue()的方式来使用全局事件总线。在Vue3中,推荐使用mitt这一三方库来帮助我们实现全局事件总线。

一、安装mitt插件

Mitt是一个微型的 EventEmitter 库,在Vue3中,官方推荐使用它替代已经移除的EventBus。

npm install mitt --save

二、主要命令有三个分别是emit、on、off

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")
})

你可能感兴趣的:(Vue,vue.js,javascript,ecmascript)