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


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

    一、安装mitt插件

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

    npm install mitt --save
    
    • 1

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

    emit(name,data) 
    //触发事件,两个参数:name:触发的方法名,data:需要传递的参数
    on(name,callback) 
    //绑定事件,两个参数:name:绑定的方法名,callback:触发后执行的回调函数
    off(name) 
    //解绑事件,一个参数:name:需要解绑的方法名
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    三、局部引入及其使用方法

    在根目录下创建一个bus.ts

    import mitt from "mitt";
    const emitter = mitt()
    export default emitter
    
    • 1
    • 2
    • 3
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    注意:在事件的触发之前,要确定事件已经被绑定,否则是找不到触发事件的。

    四、问题复现及描述

    比如我们定义 EventBus.emit,然后马上进行路由跳转,然后在下一个组件中用,你会奇异的发现这个方法压根不会触发。也就是说mitt,emit触发第一次,on监听不到。

    分析:因为emit 先于 on 执行了,VUE并没有储存监听事件,所以无法监听到数据。

    我这里遇到的是在调用emit的时候子组件并没有创建,所以无法监听到数据,子组件创建之后,便可以监听到传递过来的数据。

    我的解决方法是在调用emit的时候,使用 nextTick()方法

    用法:将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。

    nextTick(() => {
      emitter.emit("setHomeChart", {
    		**, **
    		...
       });
     });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    解决方案:

    把emitter.on也放在setup里面,先监听,再发送消息,就可以监听到了。

    emitter.on('setHomeChart', (message: any) => {
        console.log(message, "message");
    })
    
    • 1
    • 2
    • 3

    五、另一种思路

    如果写在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
            }
        })
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    事件总线是全局的 也就是说 当你每次emit触发一次这条线就已经创建存在了 当整个程序在运行时他就会一直存在 每当你触发一次就会新建一条事件总线 也是为什么会触发多次函数的问题所在。如果需要移除,可在组件销毁前销毁当前事件总线。

    onBeforeUnmount(()=>{
       emitter.off("setHomeChart")
    })
    
    • 1
    • 2
    • 3
  • 相关阅读:
    Vue3 企业级优雅实战 - 组件库框架 - 6 搭建example环境
    [自学记录06|*Animation]四元数、死锁与方位插值
    基于SpringBoot的教师工作量管理系统
    Springboot 集成 MongoDB
    (一分钟看懂4种拒绝策略) java多线程拒绝策略
    韩顺平-多态
    Anaconda配置镜像源
    java-net-php-python-springboot健身房管理系统计算机毕业设计程序
    AcWing第 79 场周赛
    Java使用hutool工具类发送网络请求
  • 原文地址:https://blog.csdn.net/qq_44034384/article/details/132668566