发布订阅是一种设计模式,基于事件池机制完成
- @1 往事件池中添加事件 on [去重机制]
@2 从事件池中拿出事件来执行,fire(emit)
@3 从事件池中移除事件off/remove
事件池这个对象可以有两种数据结构:
@1.是个数组,数组中的每一项是个对象,对象存储事件标志和事件方法<br /> @2.是个对象,事件标记作为属性名,属性值是个数组,数组存储所有方法
三个方法:
@1.订阅(增加方法)on
先判断事件池中有没有当前事件标志,没有就创建;有的话判断有没有绑定过这个方法,没有绑定的话再绑定(完成了去重)
@2.发布(执行方法)fire
第一参数是事件标志,后面所有参数是给执行方法传参
拿到传参的事件标志,把其中所有的方法强制改变this,并传参执行
@3.取消订阅(移除方法)off
把某个事件标志中的某个方法移除 ```javascript class subsscibe{ list={}; // on 是往事件池中添加事件 on(tag,fn){//先判断事件池中有没有相关属性,如果没有需要赋值一个空数组 if(!this.list.hasOwnProperty(tag)){ this.list[tag]=[]; }; // 判断数组中有没有当前方法 if(this.list[tag].includes(fn)) return; // 往数组中添加方法 this.list[tag].push(fn);
}; //off 是从事件池中移除事件 off(tag,fn){
// 如果当前事件类型存在 if(this.list[tag]){ // 拿到当前索引 let index=this.list[tag].indexOf(fn); if(index>-1){ // 当索引大于-1 就把这一项删除 this.list[tag].splice(index,1); } };
}; //把事件池中的函数拿出来执行 fire(tag,…params){
if(this.list[tag]){ this.list[tag].forEach(fn=>{ // 拿到事件池中的每一个方法 改变this执行并传参执行 fn()=>this window 所以要改变this的指向 fn.call(this,...params); }); }
}; };
//=============如何用
let sub=new subsscibe(); //此时方法中的this为sub实例对象
function eat1(food){
console.log(吃:${food}
);
};
function drink(){
console.log(‘喝水了’);
};
//对比addEventListener/removeEventListener 采用了事件池
// 第一个参数是事件标记,是表示不同函数的作用 sub.on(‘eat’,eat1); sub.on(‘drink’,drink); // 执行函数 并传参 sub.fire(‘eat’,’汉堡包’); sub.fire(‘drink’);
// 把eat标志的eat1方法移除 sub.off(‘eat’,eat1);
function review(str) { console.log(‘复习’+str); } //setTimeout 异步 setTimeout(() =>{ sub.on(‘review’,review); sub.fire(‘review’,’js’) sub.fire(‘review’,’vue’) sub.fire(‘review’,’react’) });
$(document).on(‘click’,function(){});//jq on 就运用了发布订阅机制 ```