以前瞭解到的事件代理很少,就像是一個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
進行往上查找並執行觸發事件的回調