以前了解到的事件代理很少,就像是一个dom将事件委托给另外一个dom,又叫事件委托。后来作了个题目,要实现一个相似jquery的事件委托方法,而后认真的了解了一下。而后专一于实现,其实并无去看jquery的源码,hhh。javascript
发布订阅模式大概是目前前端框架使用的一种最多见的设计模式了,而我目前也只对发布订阅模式有必定了解,其余的设计模式待后续学习整理。html
在jquery中,实现事件委托只须要下面这一行代码就能够搞定前端
$("#container").on('click', 'item', fn)
复制代码
以前会以为这么用理所固然,因此并无想到哪一天我会亲手去实现一个这样的功能,如今机会来了。java
题目给的很简单,就是将子节点的事件绑到其父节点上,好比下面这段dom,就是将<li>
的事件绑定到<ul>
上,实现点击<li>
时触发<ul>
上的事件。jquery
<div id="container">
<li class="item" id="item1">
<span id="btn1">hello</span>
</li>
<li class="item">
<span>world</span>
</li>
</div>
复制代码
题目的js部分是这样的设计模式
!function(root, doc){
class Delegator {
constructor (selector/* root选择器 */) {
// TODO
}
on (event/* 绑定事件 */, selector/* 触发事件节点对应选择器 */, fn/* 触发函数 */) {
// TODO
}
destroy () {
// TODO
}
}
}(window,document)
复制代码
而后实现一个功能相似上面jquery的事件委托,就像下面这样的前端框架
var delegator = new Delegator('#container');
delegator.on('click', 'li.item', fnli)
复制代码
忘记一开始想的是什么方法了,反正写到一半的时候忽然想起了订阅发布模式(由于恰好那几天在看发布订阅模式),而后开始撸代码。框架
分解上面的方法,其实能够看做是一个监听器dom
delegator.addEventListener('click', delegatorFn)
复制代码
只不过这个delegatorFn
有点特殊,它须要遍历这个全部委托‘click’事件给delegator
的子节点,并执行他们的委托fnli
函数
首先,咱们把全部的委托看成是一个订阅事件,只不过这个事件里包含了委托者。在Delegator
对象的原型里增长一个属性eventObj
,里面存放订阅‘click’事件的全部的委托者和委托事件,结构差很少是这样的
this.eventObj.click=[{
selecter:'li.item',
callback:fnli
}]
复制代码
那么整个on的方法其实就是委托者selector
订阅事件并委托给调on的被委托者
on (event/* 绑定事件 */, selector/* 触发事件节点对应选择器 */, fn/* 触发函数 */) {
// TODO
if(!this.eventsObj[event]){
this.eventsObj[event] = [];
}
this.eventsObj[event].push({
selector,
callback: fn
})
//这里委托事件给this.root,当被委托者坚挺到event事件时,会触发委托函数delegatorFn
this.root.addEventListener(event, delegatorFn);
//由于on能够链式调用,因此这里须要返回
return this;
}
复制代码
如今须要实现delegatorFn
方法了,其实也很简单,主要是遍历事件通过的全部dom中哪一个selector
订阅了它,它就执行对应节点携带的fn
。
delegatorFn = (e) => {
let target = e.target;//触发事件的selector
let currentTarget = e.currentTarget; //被委托者
//判断触发事件的节点及它冒泡通过的节点是不是被委托者,如果,则表示再也不有委托者,无需遍历
while(target !== currentTarget){
this.eventsObj[e.type].forEach(item => {
//查找订阅事件者
if(target.matches(item.selector)){
//执行订阅事件者携带的函数
item.callback.call(target,e);
}
});
//往上冒泡
target = target.parentNode;
}
}
复制代码
以上,就是经过发布订阅实现的事件委托的核心部分,主要涉及的还有事件的冒泡。
主要涉及知识点:
e.target
进行往上查找并执行触发事件的回调