记一个坑:使用$emit和$on多次调用Vue方法的问题

1、问题总结 :

​ vue3项目中使用mitt作为组件之间的通信,页面A中的onMounted生命周期里emit.on()监听事件,页面B(或JS文件)中调用时,多次调用了vue的方法。

​ bug复现:在该项目中多次进入页面A,然后使用emit触发监听的事件。

2、mitt的使用

  • 引入

    1
    2
    3
    import mitt from "mitt";
    const emitter = mitt();
    export default emitter;
  • 使用

    1
    2
    3
    4
    5
    6
    7
    // 页面A

    import emitter from "@/utils/emit";

    onMounted(async () => {
    emitter.on("refreshH5", getCompletionInfo);
    });
    1
    2
    3
    4
    5
    6
    // 页面B || 其他组件 || 其他js文件

    import emitter from "@/utils/emit";


    emitter.emit("refreshH5");
  • 总结:将mitt方法要做的事做个比喻,该库的作用好比一辆公交车,上面的东西任意取用($on),如果你有什么信息需要传达出去也可以将至放在($emit)车上;如果不想公开了也可以把它撤下来($off)。

    1
    2
    3
    4
    // 使用方法
    $emit('eventName', argsobj); // 如果传两个参数,那么fn(res),res将是一个数组: argsobj1,argsobj2]
    $on('eventName', fn);
    $off('eventName', fn);

3、踩坑后,思路总结:

  • 发现多次调用事件后,一直是在组件里去销毁事件,发现这样销毁并不彻底;相当于是进入A页面一次,emitter.on就被执行一次,相当于是造了一辆车,那么多次进入就相当于造了多辆一模一样的车(误区:我以为会覆盖),然后我在其他组件使用emitter.emit(一枚钥匙),然而这一枚钥匙启动了多辆车,事件执行了多次。

  • 解决办法:

    1
    2
    3
    4
    5
    // 页面销毁时必须删除事件处理程序

    onBeforeUnmount(() => {
    emitter.off("refreshH5", getCompletionInfo)
    })