之前我们实现了子组件向父组件传递数据,很明显,这是不够的,看完这篇博客,无论哪两个组件之间传递和接收数据都没有问题!
全局事件总线(适用于任意组件间通信) 原理:(看图理解)
主要就是通过往 x 身上放事件,然后事件的回调要放在想要获取数据的组件身上,谁要传数据就调用 x 身上对应的事件并往里面存数据就可以了,相当于一个中间商(哎,不得不说,它一出生就被利用了)
当然不是谁都能但此大任的,x 需要具备两个条件:
-
所有组件都可以看到
-
x 身上有 on、on 、on、off 、$emit 方法
统一给 x 命名为 $bus
我们将其定义在 main.js 文件中,创建在 vm 的实例对象身上,因为 vm 实例对象只有一个
创建全局事件总线有两种方法:
1、
const Demo = Vue.extend({})
const d = new Demo()
Vue.prototype.$bus = d
(定义在创建 Vue 的外面)
2、
new Vue({
......
beforeCreate(){
Vue.prototype.$bus = this //安装全局事件总线, $bus 就是当前应用的 vm
},
})
复制代码
new Vue({
render: h => h(App),
beforeCreate(){
Vue.prototype.$bus = this //安装全局事件总线
}
}).$mount('#app')
复制代码
使用事件总线:
- 接收数据:A 组件想接收数据,则在 A 组件中给 $bus 绑定自定义事件,事件的回调留在 A 组件自身
mounted() { //或者后面指向的是一个方法,方法在 methods 里面定义 //在全局事件总线 bus中绑定一个hello事件,后面的回调是箭头函数,用于接收数据this.bus 中绑定一个 hello 事件,后面的回调是箭头函数,用于接收数据 this.bus中绑定一个hello事件,后面的回调是箭头函数,用于接收数据this.bus.$on("hello", (value) => { console.log("我获取到了数据", value); }); },
- 提供数据:
methods: { sentMyName(){ //在该方法中触发 hello 这个事件,把数据传过去 this.bus.bus.bus.emit('hello',this.myName) } }, 用这个方法的好处就是!我们就不需要再在标签里绑定自定义事件了,直接把事件在 $bus 里创建,再在要传数据的地方调用它就可以了!
当然还有个注意点,如果某个事件或绑定事件的组件你不用了,那要养成随时解绑的好习惯!不要占着空间不用,会导致空间浪费从而出现卡顿
最好在 beforeDestroy 钩子中,用 $off 去解绑当前组件所用到的事件
在绑定事件的组件中解绑(即需要数据的组件)
beforeDestroy() { //解绑 bus中名为hello的事件this.bus 中 名为 hello 的事件 this.bus中名为hello的事件this.bus.off("hello"); }, 切记!this.bus.off()里面一定要写要解绑的事件,不然off() 里面一定要写要解绑的事件,不然 off()里面一定要写要解绑的事件,不然bus 中所有的事件都会被解绑!后果很严重!!!!
消息订阅与发布(适用于任意组件间通信) 原理:
简单理解:
需要数据的组件:订阅消息 提供数据的组件:发布消息
这个相比第一种方法就要麻烦那么一丢丢了,它需要安装 pubsub,我们打开 VScode 的控制台,输入 npm i pubsub-js,进行安装
在传数据和接收数据的组件中都要通过 import pubsub from 'pubsub-js' 引入这个文件
然后就可以开始使用了
接收数据:A 组件想接收数据,则在 A 组件中订阅消息,订阅的回调留在 A 组件自身
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
console.log('我接收到数据了',data);
})
复制代码
这里有一个注意点,那就是回调函数的第一个参数 msgName,代表的是 hello,即订阅的消息名,这个必须要写,因为默认第一个参数就是消息名,第二个参数才是数据,前端培训所以不管如何,第一个要占个位,你可以给它取个名字,或者用下划线 _ 占位
提供数据:
methods: { sentMyName(){ pubsub.publish('hello',this.myName) } }, 当然如果订阅的消息不用了,也要将其删除,不能占用空间,但是删除订阅消息不是用 $off ,而是 publish.unsubscribe(this.pubId),其中 this.pubId 是每个消息创建的时候都会有一个 id,就像定时器一样,我们删除就删除它对应的 id 号就可以了
beforeDestroy() { pubsub.unsubscribe(this.pubId) }, 对比两者我们用的更多的是前者,因为它是 Vm 里面创建的,不需要再导入包
最后再分享一个方法: