总结

全局事件总线(GlobalEventBus)

  1. 一种组件间通信的方式,适用于任意组件间通信

  2. 安装全局事件总线:

    new Vue({
        ......
        beforeCreate() {
            Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
        },
        ......
    }) 
  3. 使用事件总线:

    1. 接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
      即:谁接收,谁绑定

      methods(){
        demo(data){......}
      }
      ......
      mounted() {
        this.$bus.$on('xxxx',this.demo)
      }
    2. 提供数据:this.$bus.$emit('xxxx',数据)
      即:谁提供数据,谁发射

  4. 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。

源码

main.js

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false

//084
//Vue.prototype //表示 Vue的原型对象
//Vue.prototype.x = {a:1, b:2}    //写成一个对象
//输出 Vue的原型对象
//console.log(Vue.prototype)
//所以上面的 Vue.prototype.x写成一个对象,顺着原型链找不到 Vue的原型对象
//先把 x 写成 vc(傀儡) 看看:
//写法1: vc
/*const demo = Vue.extend({})
const d = new demo()
Vue.prototype.x = d //d是一个组件的实例对象,即 vc
*/

//创建vm
//const vm = new Vue({
    new Vue({
    el:'#app',
    render: h => h(App),

    //085
    beforeCreate(){
        //写法2: 安装 全局事件总线 (因为 vc vm 都可以看到这个 $bus)
        //Vue.prototype.x = this //this 此处的this 指向就是 vm
        //一般我们不叫 x, 而是叫 bus,因为 bus 符合 x(傀儡)的气质。
        Vue.prototype.$bus = this
    }
    //081
    /*mounted(){
        setTimeout(()=>{
            this.$destroy() //此时 this 指 vm
        },3000)
    },*/
})

//如果写到这里,报错: 无法读取一个未定义的 $on 属性。 因为:写到这里已经晚了。上面 new Vue() 走完了(意味 各组件都已经放到 页面上了,也就意味着各组件中的 mounted()都已经执行完了 )再执行下面一句。
//Vue.prototype.x = vm 
//所以要使用 vm 作为 傀儡,那么需要在 beforeCreate() 中去处理

components\School.vue

<template>
    <div class="school">
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>

        <!--button @click="sndSchoolName">把学校名给App</button-->
    </div>
</template>

<script>
    export default {
        name:'SchoolVue',

        props:['getSchoolName'],

        data() {
            return {
                name:'尚硅谷',
                address:'北京',
            }
        },

        //084
        mounted(){
            console.log('School', this.x)

            //绑定自定义事件 hello:
            //如果这样在 main.js 中写 Vue.prototype.x = {a:1, b:2}:立马报错。因为 Vue的原型对象上的x 没有 $on ,就是一个普通的Object对象。 如果还往上找,就到了 Object原型,也没用 $on
            //在 School组件中 绑定了一个 hello 事件:
            //this.x.$on('hello',(data)=>{
            //085 配合写法2的写法:
            this.$bus.$on('hello',(data)=>{

                console.log('我是School组件,收到了数据',data)
            })
            //this 是 School组件的实例对象,它可以调用 $on 的原因: 组件在 Vue原型对象 上。


        },

        //085 
        //如果哪天当前组件销毁了,那么就需要在销毁前释放上面绑定的自定义事件 hello:
        beforeDestroy(){
            this.$bus.$off('hello')
        }
    }
</script>


<!-- 我们在 vue组件中写的样式,最终都被汇总在一起。此时容易出现一个问题:样式名冲突。 为了解决这个问题: 添加 scoped,表示其中的样式只负责本组件 -->
<style scoped>
    .school{
        background-color: skyblue;

        padding: 5px;
    }
</style>

components\Student.vue

<template>
    <div class="school">
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>

        <!--button @click="sndSchoolName">把学校名给App</button-->
    </div>
</template>

<script>
    export default {
        name:'SchoolVue',

        props:['getSchoolName'],

        data() {
            return {
                name:'尚硅谷',
                address:'北京',
            }
        },

        //084
        mounted(){
            console.log('School', this.x)

            //绑定自定义事件 hello:
            //如果这样在 main.js 中写 Vue.prototype.x = {a:1, b:2}:立马报错。因为 Vue的原型对象上的x 没有 $on ,就是一个普通的Object对象。 如果还往上找,就到了 Object原型,也没用 $on
            //在 School组件中 绑定了一个 hello 事件:
            //this.x.$on('hello',(data)=>{
            //085 配合写法2的写法:
            this.$bus.$on('hello',(data)=>{

                console.log('我是School组件,收到了数据',data)
            })
            //this 是 School组件的实例对象,它可以调用 $on 的原因: 组件在 Vue原型对象 上。


        },

        //085 
        //如果哪天当前组件销毁了,那么就需要在销毁前释放上面绑定的自定义事件 hello:
        beforeDestroy(){
            this.$bus.$off('hello')
        }
    }
</script>


<!-- 我们在 vue组件中写的样式,最终都被汇总在一起。此时容易出现一个问题:样式名冲突。 为了解决这个问题: 添加 scoped,表示其中的样式只负责本组件 -->
<style scoped>
    .school{
        background-color: skyblue;

        padding: 5px;
    }
</style>