总结
全局事件总线(GlobalEventBus)
一种组件间通信的方式,适用于任意组件间通信。
安装全局事件总线:
new Vue({ ...... beforeCreate() { Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm }, ...... })使用事件总线:
接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
即:谁接收,谁绑定methods(){ demo(data){......} } ...... mounted() { this.$bus.$on('xxxx',this.demo) }提供数据:
this.$bus.$emit('xxxx',数据)
即:谁提供数据,谁发射
最好在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>
                    