在使用vue-bus进行兄弟组件的数据传递过程中,遇到的问题,及解决方案 问题:vue中eventbus被多次触发,在this.$on监听事件时,内部的this发生改变导致,无法在vue实例中添加数据。
当我们从A页面跳转到B页面中的时候发生了什么?首先是B组件created 然后beforeMounted接着A组件才被销毁,A组件才仔细beforeDestory,以及destoryed。然后B组件再执行mounted。 所以我们可以把A页面组件中的emit事件放到beforeDestory里,因为这个时候,B组件的created钩子已经执行,也就可以监听到从A传过来的事件了。而且从周期来看,B的$on监听,也不能放在mounted钩子里,不然也会出现监听不到的情况。
<template>
<div>
I am AChild
<button @click="increment">emit</button>
</div>
</template>
<script>
export default {
name: 'Achild',
methods: {
increment() {
console.log('A触发了 $emit')
this.$router.push('/B')
}
},
beforeDestroy () {
this.bus.$emit('increment', '我是increment')
}
}
</script>
我们可以看到修改后,B明显可以收到A传递过来的数据。但是多次点击,事件的触发还是会依次增加,控制台打印的输出每次都有增加。而且每次在$on里的回调函数会打印出以前监听到的vue实例,和本次监听的实例。
总结
查找各方面资料,才知道$on事件是不会自动销毁的。需要我们手动来销毁。
这是因为Bus是全局的,并不随着页面的切换而重新执行生命周期,所以$on能存储到以前的实例,这样看起来才比较奇怪。如果没有A组件没有将emit放在beforeDestory钩子里,通过全局的事件总线bus(没有受生命周期约束),而B里的 $on里没有监听到最新的emit,只会收到以前的事件,所以$on的this会指向上次B.vue的vue实例。导致现在的B.vue就算看起来拿到了数据,也无法挂载到现在的B实例上。
所以在B组件添加
beforeDestroy () {
this.bus.$off('increment')
}
建议
使用bus时一定要注意,组件的生命周期。对于这种会被销毁的vue实例。一定要把emit放在beforeDestory里面。并且要记得将$on销毁。
如果是要保存这种状态最好使用vuex,进行数据传递。这样这些传递的值,就不会受组件的销毁新建的影响,可以保存下来。