vue兄弟组件通信以及eventbus
偶然间在开发项目中遇到问题,想到如果从顶层组件传一个data给底层组件,仅仅使用父子传递的方式会变得十分麻烦。
EventHub
在获取data的组件上设置一个监听器,每次要传递data时,那个组件就广播这个事件并调用这些监听器。我们不难发现EventHub的主要功能就两个:监听和广播,还有去掉监听器
let eventHub = newVue( )
// 监听
eventHub.$on('eventName,(data)=>{
console.log()
})
// 广播
eventHub.$emit('eventName',data)
//去掉监听
eventHub.$off('eventName')
具体实现
eventHub是个全局变量,具体是放到main.js里面初始化吗?还是放在vue.prototype里面直接用this.eventHub来使用?
//App.vue
import Vue from "vue";
export default {
name: "App",
components: {
GrandParent
},
data() {
return {
eventHub: new Vue()
};
},
provide() { //使用provide对外暴露这个EventHub
return {
eventHub: this.eventHub
};
},
methods: {
setRandomValue() {
this.eventHub.$emit("update:msg", Math.random() * 100);
}
}
};
然后在需要监听的组件里面用 inject注入这个依赖。
export default {
inject: ["eventHub"],
data() {
return {
msg: ""
};
},
created() {
this.eventHub.$on("update:msg", msg => {
this.msg = msg;
});
}
};
但是,如上所写代码会出现问题
- 第一次触发的时候,接收参数传值的界面on事件没有被触发
- 为什么后面再一次依次去触发的时候会出现,每一次都会发现好像之前的on事件分发都没有被撤销一样,导致每一次的事件触发执行越来越多。
原因及解决方法
- 当我们还在页面A的时候,页面B还没有生成,也就是B中的created中见提供的来自于A中的事件还没有被触发,这个时候当你A中emit事件的时候,B页面其实还没有监听到。
渲染过程:父beforeCreate–>父created–>父beforeMount–>子beforeCreate–>子created–>子beforeMount–>子mounted–>父mounted;
销毁过程:父beforeDestroy–>子beforeDestroy–>子destroyed–>父destroyed;
修改如下:
beforeDestroy () {
this.eventHub.$emit('update:msg',this.data)
}
2.因为B页面$on事件是不会自动销毁的,需要我们手动来销毁
具体如下
// 在B组件页面中添加以下语句,在组件beforeDestory的时候销毁。
beforeDestroy () {
this.eventHub.$off('update:msg')
},
总结
用eventBus 来进行页面组件之间的数据传递,需要注意三点:
1.事件名必须保持统一,也就是上述例子的update:msg;
2.组件A$emit事件应在beforeDestory生命周期内;
3.其次,组件B内的on记得要销毁。