我們收取快遞有兩種方法:一是在特定的地點等快遞的到來,二是委托人代收。現實當中,我們大都采用委托的方案。而委托人接受的委托不止一份,他會判斷收件人,從而發放到各自手中。這也就是js事件委托的通俗理解。
為啥要用事件委托?
一般來說,dom需要有事件處理程序,我們都會直接給它設事件處理程序就好了,那為什么要用事件委托呢?
獨立典型的程序或許需要單獨的處理程序,但是程序的結構越復雜龐大,就會有大量重復的程序事件。單獨直接得處理程序,會嚴重影響工作的效率。可能,我們能用for循環等方法,遍歷所以程序,但這會導致與dom節點的不斷交互,訪問dom的次數越多,引起瀏覽器重繪與重排的次數也就越多,就會延長整個頁面的交互就緒時間,這就是為什么性能優化的主要思想之一就是減少DOM操作的原因。
所以如果要用事件委托,就會將所有的操作放到js程序里面,與dom的操作就只需要交互一次,這樣就能大大的減少與dom的交互次數,提高性能
如何實現事件委托?
事件委托是利用事件的冒泡原理來實現的事件從最深的節點開始,然后逐步向上傳播至最上層的事件。
網上常見的例子
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
我們需要把li的點擊事件綁定到ul上
var ul = document.getElementById('ul')
ul.addEventListener('click', function() {})
這樣我們就實現了委托,但是有出現了新的問題,如果ul內不止li,那么處于ul內的其他元素被點擊時,事件也被觸發了!
所以我們需要在觸發事件前來一個判斷
ul.addEventListener('click', function(e)
// 檢查事件源e.targe是否為Li
if (e.target && e.target.nodeName.toUpperCase == "LI") {
// 真正的處理過程在這里
console.log("點擊成功")
}
}
這樣就大功告成了?很遺憾,這種情況還存在一個嚴重的bug,如果元素在li中呢?那么事件就不會觸發!比如這樣
<ul id="ul">
<li id="l1"><span>1</span></li>
<li id="l2">2</li>
<li id="l3">3</li>
<li id="l4">4</li>
</ul>
那么該怎么做呢?我們需要再加一個判斷,判斷點擊的元素的父輩元素中有沒有li,如果有,就繼續執行事件。
ul.addEventListener('click', function() {
let el = e.target
while (el && !el.matches(selector)) {
el = el.parentNode
if (element === el) {
el = null
}
}
if (el) {
console.log('執行回調函數')
}
}
后記
我們發現問題,然后找出方法解決問題。并不代表事件的結束,我們所用的方法也許會帶來其他的原題。多思考,多測試,不斷完善。記住,現在得到的永遠不是最佳答案。