全局事件总线

649 阅读3分钟

引入

全局事件总线是一种非常厉害,且常用的组件件通信的方式,他可以实现任意两个组件之间的数据通信,通俗来讲有点像对讲机,可以直接进行信息传递。

分析全局事件总线的实现原理

看个图分析一下,全局事件总线到底是怎么实现组件间数据的传递的吧。

2023-03-05.png 先分析一下整体结构,一个大的App组件里面,包含了A,B,D三个组件,B中又包含了一个C组件,而在它们的外部有一个“粉色滴”X组件,这个组件有点特殊,它不属于任何一个组件,独自美丽。

举个栗子,有一天A组件想收到别人给它传递的数据,这时在A里面写点代码,给小粉X组件绑定一个名为demo的自定义事件,因为是在A组件里面给小粉X绑定的自定义事件,所以demo自定义事件的回调也是留在A组件里面,这个时候D组件刚好想给A组件传递个“666”,这时在里面写点代码,触发小粉X的demo自定义事件,并且带上数据“666”,这时小粉X身上的demo事件就被触发了,那么接下来就会执行demo事件的回调,而回调在A组件身上,回调一执行,数据“666”就以参数的形式去到了A组件了。

在举个栗子,B组件也想收到别人给的数据,于是它也给小粉X组件绑定了一个test自定义事件,然后D组价又想给B组件传递一个数据“8”,于是又在D组件里面写点代码,触发小粉X的自定义事件test,并将数据“8”传递过去,小粉X的自定义事件test被触发,B组件的回调便被执行了,数据“8”也成功以参数的形式传递给了B组件。

同理A组件想给,在B组件里面的C组件传递点数据,这和上面的两个栗子方法完全相同,在C组件里面整点代码,先给小粉X绑定个自定义事件test2,A组件触发小粉X的test2自定义事件,并将数据“9”通过自定义事件的回调传递给C组件。所以说全局时间总线可以实现任意两个组件之间的数据通信

如何安装全局事件总线

这三个栗子的共同点,各种绑定事件,触发事件都靠小粉X组件,小粉X组件这么厉害,符合什么要求,才能成为小粉X组件呢?

要求1 这么厉害!绑定触发事件全靠它!通信全靠它!当然得引人注目啊,所以第一个要求就是要保证所有的组件都能够“看到”。

那么问题来了,将X放在哪才能让所有组件都看得见呢?正解就是Vue原型对象

一个重要的内置关系

VueComponet.prototype.__prop__=Vue.prototype

这个内置关系可以让组件vc访问到Vue原型身上的属性,方法

然后让我们看看代码吧:

//main.js
import Vue from 'vue'
import App from './App.vue'
//这能保证所有人都能看到x
Vue.prototype.x={a:1,b:2}

//创建vm
new Vue({
  el:'#app',
  render:h => h(App),
})
//组件实例对象school.vue
<script>
  export default {
    name: 'School',
    data() {
      return {
        name:'尚硅谷',
        address:'北京',
      }
    },
    mounted() {
      console.log('School',this.x);
    },
  }
</script>

所以小粉组件X必须要放到原型对象上,保证所有组件都能看见。

要求2 它既可以绑定事件,又可以触发事件,所以它必须包含onon和off,还有$emit

这也是为什么小粉X组件要绑在Vue原型对象的另一原因,因为它包含的内置关系,可以让vc实例访问到Vue原型的实例方法。

看看代码吧

//main.js
import Vue from 'vue'
import App from './App.vue'
//这能保证所有人都能看到x
Vue.prototype.x={a:1,b:2}

//创建vm
new Vue({
  el:'#app',
  render:h => h(App),
  beforeCreate() {
    Vue.prototype.$bus=this    //安装全局事件总线!!!
  }
})

代码分析

$bus其实小粉组件X啦,bus除了公交车的意思外,其实还有总线的意思,它就可以让所有的vc和vm都看到啦。

为什么是beforeCreate呢?beforeCreate是生命周期钩子最开头的一个,根据生命周期图可知,它的this是当前new Vue()出来的vm,在beforeCreate里,模板根本还没有开始解析,借助beforeCreate在模板解析之前,将原型上的东西给放好(安装全局事件总线)。

下面是两个兄弟组件的代码,我们要借助全局事件总线实现两个兄弟组件之间的数据传递。

//组件实例对象school.vue
<script>
  export default {
    name: 'School',
    data() {
      return {
        name:'尚硅谷',
        address:'北京',
      }
    },
    mounted() {
      this.$bus.$on('hello',(data)=>{
        console.log('我是school组件,收到了数据',data);
      })
    },
  }
</script>
//组件实例对象student.vue
<script>
  export default {
    name: 'Student',
    data() {
      return {
        name:'zs
        sex:'',
      }
    },
    methods:{
      sendStudentName(){
        this.$bus.$emit('hello')
      }
    }
  }
</script>

代码分析

sendStudentName就是自定义事件,data就是要传递的数据,这样就通过全局自定义事件实现了组件间数据的传递啦!