之前写项目中遇到使用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');
},
不过,最好两个同时加上去,不然会有问题的哦(小伙伴测试一下就知道了),所以有绑定也要有解绑!!