js 发布订阅设计模式(观察者模式)
2020-01-19 本文已影响0人
看庭前花开花落_望天上云卷云舒
一、DOM0和DOM2的核心知识
1、语法上的区别
box.onclick=function(){}
box.addEventListener('click',function(){})
2、底层运行机制上的区别
DOM0就是给元素的某个属性绑定方法(有效绑定的方法只有一个)
DOM2是基于事件池机制完成,每增加一个绑定的方法,都会往事件池中存放一个...当事件触发会一次执行事件池中的事情
=》发布订阅其实就是模拟的事件池机制(可以给同一个元素的某个事件绑定多个不同的方法)
3、dom2中可以给一些特殊的事件类型绑定方法,这些事件类型DOM0不支持绑定,例如:DOMContentLoaded、transitionend...
$(document).ready()=>$(function(){})
vs
window.onload
//二者的区别:
//前者相当于DOM2事件绑定,可以绑定多次 后者相当于dom0事件绑定 只能绑定一次;
//前者触发条件是dom加载完毕就开始触发 后者触发条件是dom结构和所有的元素都加载完成了开始触发
DOM2的事件池机制:
1、基于addEventListener/attachEvent(IE6-8)向事件池中追加方法:
新版本浏览器会根据元素和事件类型对新增的方法做重复校验,但是IE6-8不可以
2、当事件行为触发,会把事件池中的方法按照增加的顺序依次执行,但是IE6-8中执行的顺序不固定
二、jquery中发布订阅处理
<button class="submit">点我啊。。。</button>
let fn1=function(){
console.log(1)
}
let fn2=function(){
console.log(2)
}
let fn3=function(){
console.log(3)
}
$('.submit').click(function(){
fn1();
fn2();
fn3();
})
//1
//2
//3
三、基于ES6自己封装发布订阅库
//.构造函数模式
//.整体思路的实现
//.数组塌陷问题和解决办法
let _subscribe=(function(){
//=>Sub:发布订阅类
class Sub{
//=>创建一个事件池,用来存储后期需要执行的方法
constructor(){
this.$pond=[];
}
//=>向事件池中追加方法(需要去重)
add(func){
//=>判断数组中是否存在相同的有相同的会返回来true
let flag=this.$pond.some(item=>{
return item===func
});
!flag?this.$pond.push(func):null;
}
//=>从事件池中移除方法:同时需要解决数据塌陷问题
remove(func){
let $pond=this.$pond;
for(let i=0;i<$pond.length;i++){
let item = $pond[i];
if(item === func){
//=>移除(顺序不变的情况下基本只能用SPLICE了),但是不能这样写,这样会导致数组塌陷问题
//我们移除不能真移除,只能把当前项赋值未null,执行的时候我们再删除
//$pond.splice(i,1);
$pond[i]=null;
break;
}
}
}
//=>通知事件池中的方法,按照顺序依次执行,执行的时候还可以给每一个方法传递参数
fire(...args){
let $pond=this.$pond;
for(let i=0;i<$pond.length;i++){
let item=$pond[i];
//让每一个方法中的this还是当前类的实例,
if(typeof item !=='function'){
//=>此时再删除
$pond.splice(i,1);
i--;
continue;
}
item.call(this,...args);
}
}
}
//=>把Sub这个类暴露出去,new Sub()这样创建一个类的实例的时候就不用 new Sub()了,直接执行_subscribe
return function subScribe(){
return new Sub()
}
})();
使用自己封装的方法库
<button class="submit">点我啊。。。</button>
let pond=_subscribe();
document.querySelector('.submit').onclick=function(ev){
pond.fire(ev);
};
let fn1=function(){
console.log(1)
}
let fn2=function(){
console.log(2);
pond.remove(fn1);
}
let fn3=function(){
console.log(3)
}
let fn4=function(ev){
console.log(4)
}
pond.add(fn1);
pond.add(fn2);
pond.add(fn3);
pond.add(fn4);
//打印结果:第一次点击结果:1 2 3 4
// 第一次点击结果:2 3 4
注:笔记源与珠峰培训