当前位置:网站首页>全局事件总线
全局事件总线
2022-07-03 13:27:00 【十八岁讨厌编程】
原理分析
全局事件总线能实现任意两个组件间的通信
例如我们现在有如下的结构:
我们想要实现任意两组件的通信,少不了一个中介X(图中右上角的粉色圆圈)。例如现在D组件要向A组件传一点数据,过程如下:
- 在A组件里面写点代码,给X绑定一个自定义事件(假设这个自定义事件的名称和叫做demo)
- 在D中写一段代码去触发X中的demo事件
- 在触发事件的同时带点数据过去(比如说我们带个666)
- 此时数据就以参数的形式来到了A组件中
在这个过程中,我们不难发现这个类似于中介的X,是有一定的要求的:
- 他能被其他所有组件给看见
- 这个X能调用
$on(),$off(),$emit()等方法
首先我们可以讨论第一个要求怎么实现,我们有如下几种方法:
- 借用浏览器对象window,所有的组件对它一定是可视的(此方法可行,但不推荐)
- 既然对所有的组件对象可见,那么放在VueComponent构造函数的原型对象上(这个方法不可行,因为VueComponent构造函数是通过Vue.extend得来的,而每次得到的都是不同的VueComponent)
- 在上一个方法的基础上,修改源码,每出现一个新的VueComponent,就挂载一个X(此方法可行,但不推荐)
- 利用关系
VueComponent.prototype.__proto__ === Vue.prototype,也就是说我们把X放在Vue.prototype身上,那么所有的组件都可以搜寻到他。(此法推荐)
接下来我们实现第二个要求:
$on(),$off(),$emit()等方法都存在于Vue的原型对象上。
因为Vue原型对象上的属性和方法都是给Vue的实例对象(vm)或组件的实例对象(vc)用的,所以这个X我们必须创建为Vue的实例对象或者组件的实例对象。
不过我们普遍强调只能由一个Vue的实例对象,所以我们一般使用组件的实例对象来代替这个中介X
代码实现
例如我们现在有如下的组件结构:
我们想实现两个兄弟组件间的通信,Student组件将学生姓名交给School组件,步骤如下:
①首先创建好中介X
我们写在main.js中,因为Vue是在那个时候被引入的
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
const Demo = Vue.extend()
const d = new Demo()
Vue.prototype.talkHelper = d
new Vue({
render: h => h(App),
}).$mount('#app')
②接受者方(School组件)去在中介上绑定事件
School组件:
<template>
<div class="demo">
<h2>学校名称:{
{name}}</h2>
<h2>学校地址:{
{address}}</h2>
<!-- <button @click="getSchoolName(name)">点击将学校名称交给父组件App</button>-->
<hr>
</div>
</template>
<script> export default {
name:'DongBei', data(){
return {
name:'NEFU', address:'哈尔滨', } }, // props:['getSchoolName'], methods:{
studentNameDeliver(name){
console.log('School组件已经接收到了来自Studennt组件的学生名称',name) } }, mounted() {
this.talkHelper.$on('studentName',this.studentNameDeliver) } } </script>
<style > .demo {
background-color: yellow; } </style>
③发送者方(Student组件)去调用中介身上的方法
Student组件:
<template>
<div class="demo">
<h2 class="stu" >学生名称:{
{name}}</h2>
<h2 >学生年纪:{
{age}}</h2>
<button @click="deliverStudentName">把学生名称给School组件</button>
</div>
</template>
<script> export default {
name:'MyStudent', data(){
return {
name:'张三', age:18 } }, methods:{
deliverStudentName(){
this.talkHelper.$emit('studentName',this.name) } } } </script>
<style > /*.demo {*/ /* background-color: green;*/ /*}*/ </style>
最终的效果:
代码优化

在此处单独创建一个组件实例对象vc太麻烦,我们不如就使用Vue的实例对象vm来作为这个中介。

不过这么写是有错误的。时机有点晚了!因为当前三行vm创建完毕之后,App组件整个都已经放在页面上去了,这就意味着School组件上的mounted都已经执行完了!
此时你再去Vue的原型对象上放一个中介已经晚了!
所以说这个中介放入的时机非常的重要,它既要在vm定义之后,又要在App组件放入之前。所以这个时候我们就想到了要用生命周期钩子!

我们选择使用beforeCreate(),这个时候模板还没有开始解析
于是我们改进后的代码如下:
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// const Demo = Vue.extend()
// const d = new Demo()
//
// Vue.prototype.talkHelper = d
new Vue({
render: h => h(App),
beforeCreate() {
Vue.prototype.talkHelper = this
}
}).$mount('#app')
这个中介其实就是全局事件总线,我们一般用$bus来进行标识
也就是说如上的代码我们应该写成:
还有一个注意点:在组件销毁之前,我们应该把其绑定在全局事件总线上的事件给解绑!
在自定义事件中我们说解绑这个操作是可有可无的,因为当组件销毁死亡之后,其身上的自定义事件自然就会消失。但是这里的全局事件总线他是一直存在的,即使有一个组件销毁了,但是绑定在全局事件总线上的事件还在,这就会造成资源的浪费。所以在这里我们推荐:在组件销毁之前,我们应该把其绑定在全局事件总线上的事件给解绑
我们使用beforeDestroy()生命周期钩子来执行解绑操作:
<template>
<div class="demo">
<h2>学校名称:{
{name}}</h2>
<h2>学校地址:{
{address}}</h2>
<hr>
</div>
</template>
<script> export default {
name:'DongBei', data(){
return {
name:'NEFU', address:'哈尔滨', } }, methods:{
studentNameDeliver(name){
console.log('School组件已经接收到了来自Studennt组件的学生名称',name) } }, mounted() {
this.talkHelper.$on('studentName',this.studentNameDeliver) }, beforeDestroy() {
this.talkHelper.$off('studentName') } } </script>
<style > .demo {
background-color: yellow; } </style>
总结
全局事件总线(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去解绑当前组件所用到的事件。
边栏推荐
- Resource Cost Optimization Practice of R & D team
- Students who do not understand the code can also send their own token, which is easy to learn BSC
- 顺序表(C语言实现)
- Go language web development series 28: solve cross domain access of CORS with gin contrib / CORS
- logback日志的整理
- [556. Next larger element III]
- Go: send the get request and parse the return JSON (go1.16.4)
- 静态链表(数组的下标代替指针)
- Go language unit test 5: go language uses go sqlmock and Gorm to do database query mock
- Depth and breadth first traversal of tree (regardless of binary tree)
猜你喜欢

Mobile phones and computers can be used, whole people, spoof code connections, "won't you Baidu for a while" teach you to use Baidu

GoLand 2021.1: rename the go project

Flutter动态化 | Fair 2.5.0 新版本特性

Logback log sorting

Qt学习25 布局管理器(四)

There is nothing new under the sun. Can the meta universe go higher?

PhpMyAdmin stage file contains analysis traceability

如何使用lxml判断网站公告是否更新

Unable to stop it, domestic chips have made another breakthrough, and some links have reached 4nm

SQL Injection (GET/Select)
随机推荐
Thrift threadmanager and three monitors
UiO-66-COOH装载苯达莫司汀|羟基磷灰石( HA) 包裹MIL-53(Fe)纳米粒子|装载黄芩苷锰基金属有机骨架材料
Comprehensively develop the main channel of digital economy and digital group, and actively promote the utonmos digital Tibet market
mysql中的字段问题
“又土又穷”的草根高校,凭什么被称为“东北小清华”?
IBEM mathematical formula detection data set
Brief analysis of tensorboard visual processing cases
How to promote the progress of project collaboration | community essay solicitation
Go language web development series 27: Gin framework: using gin swagger to implement interface documents
page owner特性浅析
Unity EmbeddedBrowser浏览器插件事件通讯
Go language unit test 3: go language uses gocovey library to do unit test
Flutter动态化 | Fair 2.5.0 新版本特性
Halcon combined with C # to detect surface defects -- Halcon routine autobahn
[quantitative trading] permanent portfolio, turtle trading rules reading, back testing and discussion
Common network state detection and analysis tools
[556. Next larger element III]
ThreadPoolExecutor realizes multi-threaded concurrency and obtains the return value (elegant and concise way)
SQL Injection (AJAX/JSON/jQuery)
交联环糊精金属有机骨架负载甲氨蝶呤缓释微粒|金属-有机多孔材料UiO-66负载黄酮苷类药物|齐岳
