一、场景描述
之前我们学习了,通过props实现父子组件之间的通信。通过自定义组件,实现了子给父传递数据。
 那么,兄弟关系的组件,如何通信了?任意组件间如何通信了?
 这个时候,就要学习全局事件总线。
 它不是一个新的API,更像是一种解决方案。
 如下图:
 
二、X的要求及选择
要求
1、所有组件都能访问到这个X。
 2、X能够调用$on、$off、$emit方法。
选择
1、所有组件都能访问
 1.1、window对象
main.js文件
window.x = {a:1,b:2}
这样,所有组件都可以访问到。
 但是,不推荐。
 而且,window对象上无法满足条件2.
 1.2、VueComponent原型
main.js文件
VueComponent.prototype.x = {a:1,b:2}
这样写,会直接报错,说VueComponent没有被定义。
 为什么了?
 因为,VueComponent是通过Vue.extend创建的。
 并且,每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
 所以,这个行不通。
 1.3、Vue原型对象
main.js文件
Vue.prototype.x = {a:1,b:2}
首先,我们要知道每个组件都对应一个vc实例对象。
 而vc和Vue原型对象有这样的一个关系:
 一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype。
 这样就可以让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
 即下图:
 
 所以,X应该添加在Vue原型对象上。
 2、能够调用$on、$off、$emit方法
 能满足这个条件的,只有vm或者vc。
选择vc作为X
 main.js
const Demo = Vue.extend({});
const d = new Demo();
Vue.prototype.x = d;
School组件
        mounted(){
            this.x.$on('test',(data)=>{
                console.log('我是School组件,收到了数据!',data);
            })
        }
Student组件
        methods: {
            sendStudentName(){
                this.x.$emit('test',this.name)
            }
        }
看效果:
 
 这样,其实已经实现了兄弟间传递数据。
但是,我们不推荐。
 因为main.js里面已经有vm实例对象了。
 所以,我们为什么不直接使用vm来实现这个效果了?
选择vm作为X
 main.js
new Vue({
    el:"#app",
    render: h => h(App),
    beforeCreate() {
        Vue.prototype.x = this;
    }
});
看效果:
 
 最终X的代码实现:
 main.js
new Vue({
    el:"#app",
    render: h => h(App),
    beforeCreate() {
        Vue.prototype.$bus = this;     //安装全局总线
    }
});
此处的$bus就是X
三、注意点
1、我们每个组件给$bus绑定事件名时,要避免重名。
 所以,我们一般需要定义一个配置文件,把全局的所有事件名写入这个文件,这样,团队开发,就不会冲突。
2、组件销毁前,解绑事件。
 School组件
        beforeDestroy(){
            this.$bus.$off('test');
        }
四、使用方法总结
A组件接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件对应的回调函数写在A组件中,组件销毁前解绑$bus上对应的事件。
methods(){
  demo(data){......}
}
mounted() {
  this.$bus.$on('xxxx',this.demo)
}
beforeDestroy(){
  this.$bus.$off('xxxx');
}
B组件提供数据:this.$bus.$emit('xxxx',数据)



















