发布订阅
所有的设计模式都是“锦上添花”;没有设计模式也可以实现需求,只不过基于设计模式可以更高效的管理代码!!
定义
发布订阅设计模式:
-
制定一个计划表「创建一个容器」
-
在没有通知计划执行之前,我们把后续要做的事情,逐一添加到计划表中!「添加到容器中」
-
在指定阶段,通知计划表中的方法逐一执行即可!!
-
也有人说,发布订阅就是模拟DOM2的事件池机制{只能处理浏览器标准事件},实现自定义事件的管理!!
原理
发布订阅是一种设计模式,基于事件池机制完成
-
往事件池中添加事件 on [去重机制]
-
从事件池中拿出事件来执行,fire(emit)
-
从事件池中移除事件off/remove
详解
四个东西:一个对象(事件池),3个方法:订阅(增加)、发布(执行)、取消订阅(移除)
一个对象(事件池)
事件池这个对象可以有两种数据结构:
-
是个数组,数组中的每一项是个对象,对象存储事件标志和事件方法
-
是个对象,事件标记作为属性名,属性值是个数组,数组存储所有方法
三个方法
-
订阅(增加方法)on
- 先判断事件池中有没有当前事件标志,没有就创建;有的话判断有没有绑定过这个方法,没有绑定的话再绑定(完成了去重)
-
发布(执行方法)fire
-
第一参数是事件标志,后面所有参数是给执行方法传参
-
拿到传参的事件标志,把其中所有的方法强制改变this,并传参执行
-
-
取消订阅(移除方法)off
- 把某个事件标志中的某个方法移除
实现
Class实现
思路
-
往事件池中添加事件
-
先判断事件池中有没有相关属性,如果没有,需要赋值空数组
-
判断数组中有没有当前方法
-
往数组中添加方法
-
-
从事件池中移除事件
-
如果当前事件类型存在
-
拿到当前项索引
-
当索引>-1,就把这一项删除
-
-
把事件池中的函数拿出来执行
- 拿到事件池中每一个方法,改变this指向并传参执行
代码实现
class Subscribe {
list = {};
on(tag, fn) {
if (!this.list.hasOwnProperty(tag)) {
this.list[tag] = [];
}
if (this.list[tag].includes(fn)) return;
this.list[tag].push(fn);
}
off(tag, fn) {
if (this.list[tag]) {
let i = this.list[tag].indexOf(fn);
if (i > -1) {
this.list[tag].splice(i, 1);
}
}
}
fire(tag, ...params) {
if (this.list[tag]) {
this.list[tag].forEach(fn => {
fn.call(this,...params);
});
}
}
}
对象实现
思路
-
全局只有一个事件池,是一个对象
-
向事件池中添加方法
-
事件池里如果还没有该标记
-
就让该标记添加到事件池里,初始值为空数组
-
重复的内容,不能添加到事件池里
-
-
执行事件池中方法
-
从事件池中取出标记值(数组)
-
标记值,空数组,中断
-
循环每一项
-
不是函数
-
删除元素,会有数组塌陷问题
-
-
删除事件池中方法
-
从事件池中取出标记值(数组)
-
标记值,空数组,中断
-
循环每一项
-
数组塌陷 直接设置为null
-
-
暴露API
-
兼容浏览器
代码实现
(function(){
let pond={};
const on=function on(tag,fn){
if(!pond.hasOwnProperty(tag)){
pond[tag]=[];
}
if(pond[tag].includes(fn)){return}
pond[tag].push(fn);
console.log(pond);
}
const fire=function fire(tag,...params){
let arr=pond[tag]||[];
if(arr.length==0){return}
let item,i;
for(i=0;i<arr.length;i++){
item=arr[i];//f1,f2
if(typeof item=="function"){
item(...params);//f1(...params)
}else{
arr.splice(i,1);
i--;
}
}
}
const off=function off(tag,fn){
let arr=pond[tag]||[];
if(arr.length==0){return}
let item,i;
for(i=0;i<arr.length;i++){
item=arr[i];
if(item==fn){
//arr.splice(i,1);、
arr[i]=null;
}
}
}
let sub={
on,
fire,
off
}
if(typeof window!==undefined){
window.sub=sub;
}
//nodejs webpack
if (typeof module === 'object' && typeof module.exports === 'object'){
module.exports=sub;
}
})()
转载自:https://juejin.cn/post/7176903865755762744