12全局事件总线、消息订阅与发布
1、全局事件总线(GlobalEventBus)
不是新的API
是程序员在开发过程中总结的经验
实现了各个组件之间的通信
1.1 设计思路
1) 需求
假设D组件要传送数据给A组件
子传数据给父,回调函数在父中

2) 对x的要求
必须得保证每个组件都能看得到它
x身上必须有$on $off $emit
3)开始设计
需要App组件以及它的所有子组件都要看得到,那么就找到App组件的上一级 ==> main.js
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
// 设计思想一
window.x = {a:1,b:2} 满足条件一,不满足条件二
// 设计思想二
VueComponent.prototype.x = {a:1,b:2} 会出现报错
//创建vm
new Vue({
el:'#app',
render: h => h(App),
})
- 设计思想二为什么会出现报错,该文件中的
vue是通过导入进来的库中暴露的全局变量,而VueComponent并没有,并且它是通过vue.extend生成的,每一次组件标签出现时,都会帮我们调用vue.extend,每次调用都会返回一个新的VueComponent - 也就是说多个vc实例对象对应多个
VueComponent,每个VueComponent中的数据都不一样
设计思想三
在源码中找到VueComponent,改成sub.prototype.x = {a:1,b:2}
不可以这样子,如果这样还不如改成window.x
VueComponent是构造函数,也就是类,vc是类的不同实例, 类的原型上加的东西,实例vc可以用__ proto__访问
设计思想四(部份正确的)
由于VueComponent.prototype.__prp__ = Vue.prototype
因此Vue上面的方法,vc实例对象都可以访问
因此vc vm 都可以访问到Vue.prototype,因此在Vue.prototype添加方法x
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
Vue.prototype.x = vc/vm ?
new Vue({
render: h => h(App),
}).$mount('#app')
- 为什么不等于
Vue.prototype??
1)首先选择vc
可以被所有组件访问到x,并且可以访问到Vue.prototype中的$on $emit $off这些方法
但是这样子写太麻烦了
因为这个x只想把它当成傀儡使用,不需要去传入具体的数据监测、数据代理等等数据
这个x的添加,必须是在new 之后,传送具体的对象之前,因此选用生命周期beforeCreate函数比较合适
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
const demo = Vue.extends({})
const d = new demo
Vue.prototype.x = d
new Vue({
render: h => h(App),
}).$mount('#app')
2)选择vm
import Vue from 'vue'
import App from './App.vue'
// Vue.prototype.x = vm 这个时候vm还没有定义,会出现报错
const vm = new Vue({
render: h => h(App),
}).$mount('#app')
// Vue.prototype.x = vm 这个时候App组件以及其他组件都已经执行完毕了,此时找不到$on $emit这些方法
- 不应该找不到x吗?
3)选择vm (正确方法)
import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this // 安装全局事件总线
}
}).$mount('#app')
1.2 事件总线
当事件总线安装上以后
某个组件使用该事件总线,往上面绑定了事件以后,用完之后最好给它销毁掉
因为如果该组件被销毁了,由于事件总线还在,该事件就也还在,还占用着该名称,如果其他组件想要新建该名字的事件,无法新建
但是为什么自定义事件无需销毁,因为自定义事件是给该组件实例对象绑定的,该组件被销毁了,也就是该组件实例对象被销毁了,自定义事件自然不见了
基本使用和ref的使用方法类似
1.3 总结
-
一种组件间通信的方式,适用于任意组件间通信。
-
安装全局事件总线:
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去解绑当前组件所用到的事件。
父亲给儿子 —— props
儿子给父亲 —— props、自定义事件
父亲给孙子、兄弟 —— 事件总线
2、消息订阅与发布
消息订阅与发布与消息总线是相反的
发布才是应用,订阅的时候,订阅回调是在本身的
订阅消息:消息名称(挂载函数)
发布消息:消息(点击事件)
订阅报纸:地址
发布报纸:报纸
感觉像是事件总线的封装,更推荐用消息总线 ==》 还是要看看,面试可能会问
-
一种组件间通信的方式,适用于任意组件间通信。
-
使用步骤:
-
安装pubsub库:
npm i pubsub-js -
在需要订阅与发布的组件中引入:
import pubsub from 'pubsub-js' -
接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
methods(){ demo(data){......} } ...... mounted() { this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息 } -
提供数据:
pubsub.publish('xxx',数据) -
最好在beforeDestroy钩子中,用
PubSub.unsubscribe(pid)去取消订阅。 ==> 销毁的时候它接收的是id,并不是事件名称,因此需要去this.pid去接收1.一般在订阅中使用该钩子去取消订阅
mounted() { // console.log('School',this) this.pubId = pubsub.subscribe('hello',(msgName,data)=>{ console.log(this) // console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data) }) }, beforeDestroy() { // this.$bus.$off('hello') pubsub.unsubscribe(this.pubId) },- 有人发布该消息之后,就会执行这个回调函数,该回调函数可以接受两个参数,第一个参数是消息名称,第二个参数是要传的参数
-
浙公网安备 33010602011771号