组件通信之全局事件总线(用于兄弟或者嵌套层级组件传值)

597 阅读1分钟

思路:各种组件间想要通信,可以利用一个第三方。比如说,A组件想给B组件传值,B组件先通过这个第三方利用$on绑定自定义事件,然会B组件会有一个回调函数,A组件再通过$emit触发这个自定义事件,用参数的形式把值带过去,B组件将会在回调函数中接收到它。

1.那么问题来了:这个第三方($EventBus)应该满足什么条件呢?

1.要保证所有的组件都能看见它($EventBus)
2.要保证它身上有$on,$emit,$off

2.继续探索。。。

怎样才能保证所有的组件能看到它呢?

1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype

2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

怎样才能保证它能调用$on,$off,$emit呢?

必须是那个创建组件,组件自动给你生成的VueComponent,也就是通过Vue.extend()生成的,但是每个组件生成的VC都不唯一,所以后面就利用vm,也就是new Vue中的this指向vm,且唯一

综上所述,这个$EventBus因该设计为:

new Vue({
    render: h => h(App),
    beforeCreate() {
        Vue.prototype.$EventBus = this //安装全局事件总线
    },
}).$mount('#app')

3.组件传值步骤

1. 安装全局事件总线

new Vue({
   render: h => h(App),
   beforeCreate() {
       Vue.prototype.$EventBus = this //安装全局事件总线
   },
}).$mount('#app')

2.在接收值的那个组件身上用$on绑定自定义事件

<template>
	<div class="student">
		<h3>我是Student组件</h3>
        <ul v-for="(p,index) in person" :key="index">
            <li>{{p.name}}</li>
            <li>{{p.id}}</li>
            <li>{{p.age}}</li>
        </ul>
	</div>
</template>

<script>
	export default {
		name:'Student',
		data() {
			return {
                person:''
			}
		},
        mounted() {
            this.$EventBus.$on('sendPMessage',(data)=>{
                console.log('我收到了School传来的数据',data);
                this.person = data;
            })
        },
        beforeDestroy() {
			this.$bus.$off('hello')
		},
	}
</script>

3.在发送值的那个组件身上用$emit去触发自定义事件,并携带需要传的参数

<button @click="sendPersonMessage">把perdon信息给student组件</button>

<script>
	export default {
		name:'School',
		data() {
			return {
				person:[
                    {id:'001',name:'小明',age:11},
                    {id:'002',name:'小红',age:11},
                    {id:'003',name:'小黄',age:11},
                ]
			}
		},
        methods:{
            sendPersonMessage(){
                this.$EventBus.$emit('sendPMessage',this.person)
            }
        }
	}
</script>

补充

  1. 使用事件总线:

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

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

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