您的当前位置:首页正文

Vue——eventBus使用,重复触发

2024-11-08 来源:个人技术集锦

之前写项目中遇到使用eventBus,兄弟组件之间传值出现问题,写了个简单的demo测试总结一下

新建了一个Bus

import Vue from "vue";
export default new Vue();

Send组件:

<template>
  <div>
    <div> 我是发送数据的页面</div>
    <div class="send" @click="send">去接收页面</div>
  </div>
</template>

<script>
  import Bus from '@/bus';
  var sendTimes = 0;//发送的次数
  export default {
    data() {
      return {
        data: {
          code: 200,
          sendData: '我是数据包!'
        },
      }
    },
    methods: {
      send() {
        Bus.$emit('send', this.data);
        console.log(`数据第${sendTimes++}次发送成功!`);  
        this.$router.push('/receive');
      }
    }
  }

</script>

Receive组件:

<template>
  <div>
    <div>我是接收的页面</div>
    <router-link :to="{name:'Send'}">返回发送页</router-link>
  </div>
</template>

<script>
  import Bus from '@/bus';
  export default {
    data() {
      return {
        receivedData: ''
      }
    },
    methods: {},
    created() {
      Bus.$on('send', (data) => {
        if (data) {
          console.log(`接收到的数据:`);
          console.log(data);
        } else {
          console.log('警告,没有接收到数据!!!!');
        }
      });
    }
  }

</script>

点击了4次的结果:

那么问题来了:
1、第一次点击,只有路由变化,没有数据传递过来也就是Receive组件的监听on么有触发;
2、第二次点击,数据正常传过来了;
3、第三次点击,数据也传过来了,但是传了2次;
4、第四次点击,数据也传过来了,但是传了3次;
不用想,接下来肯定数据重复传递。

后来,我先测试了一下两个组件的生命周期:
Send组件:

  beforeCreate() {
      console.group('%c%s', 'color:blue', 'beforeCreate 创建前状态===============组件Send》')
    },
    created() {
      console.group('%c%s', 'color:blue', 'created 创建完毕状态===============组件Send》')
    },
    beforeMount() {
      console.group('%c%s', 'color:blue', 'beforeMount 挂载前状态===============组件Send》')
    },
    mounted() {
      console.group('%c%s', 'color:blue', 'mounted 挂载状态===============组件Send》')
    },
    beforeUpdate() {
      console.group('%c%s', 'color:blue', 'beforeUpdate 更新前状态===============组件Send》')
    },
    updated() {
      console.group('%c%s', 'color:blue', 'updated 更新状态===============组件Send》')
    },
    beforeDestroy() {
      console.group('%c%s', 'color:blue', 'beforeDestroy 破前状态===============组件Send》')
    },
    destroyed() {
      console.group('%c%s', 'color:blue', 'destroyed 破坏状态===============组件Send》')
    } 

Receive组件:

  beforeCreate() {
      console.group('%c%s', 'color:red', 'beforeCreate 创建前状态===============组件Receive》')
    },
    created() {
      console.group('%c%s', 'color:red', 'created 创建完毕状态===============组件Receive》')
    },
    beforeMount() {
      console.group('%c%s', 'color:red', 'beforeMount 挂载前状态===============组件Receive》')
    },
    mounted() {
      console.group('%c%s', 'color:red', 'mounted 挂载状态===============组件Receive》')
    },
    beforeUpdate() {
      console.group('%c%s', 'color:red', 'beforeUpdate 更新前状态===============组件Receive》')
    },
    updated() {
      console.group('%c%s', 'color:red', 'updated 更新状态===============组件Receive》')
    },
    beforeDestroy() {
      console.group('%c%s', 'color:red', 'beforeDestroy 破前状态===============组件Receive》')
    },
    destroyed() {
      console.group('%c%s', 'color:red', 'destroyed 破坏状态===============组件Receive》')
    } 

可以看到,我在给Send组件 emit 时,Receive组件还没被创建,所以Receive的on监听的事件还没有被触发,这个时候当我Send中emit事件的时候,Receive其实是没有监听到的。

再看一下,红色的是Receive页面组件,当你从页面Send到页面Receive跳转的时候,发生了什么?首先是先Receive组件先created然后beforeMount接着Send组件才被销毁,Send组件才执行beforeDestory,以及destoryed.

所以,我们可以把Send页面组件中的emit事件写在beforeDestory中去。因为这个时候,Receive页面组件已经被created了,也就是我们写的$on事件已经触发了

所以可以,在Send组件beforeDestory的时候,$emit事件。

methods: {
      send() {
        console.log(`数据第${sendTimes++}次发送成功!`);
        this.$router.push('/receive');
      }
    },
     beforeDestroy() {
       console.log('准备发送了!!!');
       Bus.$emit('send', this.data);
       //Bus.$off('send');
     },

结果:相比刚开始的运行结果,第一次数据发送成功,只是,仍然会触发重复;

解决就是$on不会自己销毁,需要我们手动给销毁。就类似JQ里面on监听点击事件,如果点击事件里面嵌套一个点击就会重复触发,所以需要在嵌套点击之前解除绑定

使用$off 来解除监听:

可以给Receive组件的添加:

beforeDestroy() {
        Bus.$off('send');
    },

或者给Send组件添加,beforeDestory的时候,Receive已经创建,监听并执行了,使用Send可以解除监听:

 beforeDestroy() {
      console.log('准备发送了!!!');
      Bus.$emit('send', this.data);
      Bus.$off('send');
    },

不过,最好两个同时加上去,不然会有问题的哦(小伙伴测试一下就知道了),所以有绑定也要有解绑!!

Top