前言
看了很多发布订阅模式的文章,每次看完都脑子发懵,为什么看完不过脑啊!我觉得大概率的原因是那些文章举的例子都离我太远了,以至于我都不知道我什么时候会用到。
这个系列可是 《不背八股系列》,要的就是你看完之后不再是去背诵这个知识点,更多的是去理解并能真正应用这个知识点。话不多说,让我们赶紧进入正题吧~
正题
“发布订阅” 听起来就挺抽象的,但是如果是熟悉用vue的小伙伴,对$on和$emit应该不会觉得陌生吧。没错,他们俩就是一个东西,一个是概念,一个是实际的应用,$on和$emit就是“发布订阅”模式的具体实现。下面我就举几个大家平时开发中总能用到的例子,来带大家看看这个 “抽象” 的发布订阅到底是个啥,有什么用?
-
Vue开发中的应用
- 父子间通信:当父组件需要用到子组件的数据时,要怎么实现子组件数据向父组件传递呢?日常开发中我们一般采用的就是自定义事件,那我们就会使用
v-on:自定义事件 = "cb"这样的形式来绑定事件(到这里如果大家会想:“这里绑定事件是绑定到谁身上呢”,那就证明大家真的在认真思考!)这里我查看了vue的相关源码,发现只要是v-xxx指令,其实都是绑定在我们使用的VNode身上,这也就是我们平时在<input>标签使用@input = (e)=>e.target能获取到这个target的原因,所以这里的自定义事件其实是绑定到了子组件的vm实例身上,那么接下来绑定到了vm实例身上的事件通过this.$emit(自定义事件,参数)来通知触发,就像下图。
注意: 这里面其实缺省了一个很重要的步骤,就是到底是谁来触发这个回调的,大家平时开发都会默认的想:“子组件emit,那父组件同名的事件就会触发回调,就可以拿到数据啦~”
关键点: 弄清楚是谁调用这个回调,那么我们的正题 “发布订阅”模式 你就明白了。 - 父子间通信:当父组件需要用到子组件的数据时,要怎么实现子组件数据向父组件传递呢?日常开发中我们一般采用的就是自定义事件,那我们就会使用
做一个试试?
前面说到子组件和父组件之间通信缺少一个很重要的步骤,这个步骤涉及到两个问题:
- 父组件中的
callback是怎么触发的? - 子组件的数据又是怎么让父组件的
callback使用到的呢?
仔细看上面的两个问题,我们可以想到一个方法,那就是把父组件的callback给存到子组件中,让子组件传入子组件的数据作为父组件的callback的参数来调用,从而实现父组件的callback使用到子组件的数据,那么我们这个步骤就填上了!没错,Vue其实就是这么做的,这也就是发布订阅模式了!
还不理解的小伙伴不用急,我们还有代码实操(代码胜千言!),来实现一下超级简易的发布订阅模式的代码
class EventCenter {
constructor() {
this.eventCt = {}
}
/**
* @param {String} event 订阅事件
* @param {Function} cb 事件触发时执行的回调
*/
$on(event, cb) {
// 事件中心没有存该事件,就给他存个事件key和value为[]进去 , 将回调push进去对应的事件中
(this.eventCt[event] || (this.eventCt[event] = [])).push(cb)
// 上面这个写法我超爱!是vue源码中的写法
}
/**
* @param {String} event 触发的事件
* @param {...any} args 传递的参数
*/
$emit(event, ...args) {
// 有注册了这个事件,那就取出来在这执行了
if (this.eventCt[event].length) {
const cbs = this.eventCt[event]
cbs.forEach(cb => {
cb(...args)
});
}
}
}
const vm = new EventCenter()
// 这里可以类比父组件在子组件标签绑定 自定义事件 和 回调
vm.$on('ZiDingYi', (clickName, clickTime) => {
console.log(clickName, '在时间点:', clickTime, '触发的');
})
// 这里类比子组件使用this.$emit的过程
vm.$emit('ZiDingYi', 'charry', Date.now())
存在疑惑
到这里你应该就理解了吧!其实就是子组件的vm身上存了这个callback才能把子组件数据传到这个保存的callback来实现子组件数据传给父组件回调。
写在最后: 不过我在这里有个疑问,就是每个事件为什么要用一个数组来存这个回调呢?如果一个事件对应了多个回调,那么当触发事件时其他回调都会执行,如果还要传参岂不是每个回调都会重复触发,什么样的需求会使用到呢?有明白的小伙伴可以在评论区给我指导指导,谢谢大家的阅读~