我們收取快遞有兩種方法:一是在特定的地點(diǎn)等快遞的到來饥臂,二是委托人代收⊙吩辏現(xiàn)實(shí)當(dāng)中,我們大都采用委托的方案隅熙。而委托人接受的委托不止一份稽煤,他會(huì)判斷收件人,從而發(fā)放到各自手中囚戚。這也就是js事件委托的通俗理解酵熙。
為啥要用事件委托?
一般來說驰坊,dom需要有事件處理程序匾二,我們都會(huì)直接給它設(shè)事件處理程序就好了,那為什么要用事件委托呢拳芙?
獨(dú)立典型的程序或許需要單獨(dú)的處理程序察藐,但是程序的結(jié)構(gòu)越復(fù)雜龐大,就會(huì)有大量重復(fù)的程序事件舟扎。單獨(dú)直接得處理程序分飞,會(huì)嚴(yán)重影響工作的效率《孟蓿可能譬猫,我們能用for循環(huán)等方法,遍歷所以程序邦泄,但這會(huì)導(dǎo)致與dom節(jié)點(diǎn)的不斷交互删窒,訪問dom的次數(shù)越多裂垦,引起瀏覽器重繪與重排的次數(shù)也就越多顺囊,就會(huì)延長(zhǎng)整個(gè)頁面的交互就緒時(shí)間,這就是為什么性能優(yōu)化的主要思想之一就是減少DOM操作的原因蕉拢。
所以如果要用事件委托特碳,就會(huì)將所有的操作放到j(luò)s程序里面,與dom的操作就只需要交互一次晕换,這樣就能大大的減少與dom的交互次數(shù)午乓,提高性能
如何實(shí)現(xiàn)事件委托?
事件委托是利用事件的冒泡原理來實(shí)現(xiàn)的事件從最深的節(jié)點(diǎn)開始闸准,然后逐步向上傳播至最上層的事件益愈。
網(wǎng)上常見的例子
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
我們需要把li的點(diǎn)擊事件綁定到ul上
var ul = document.getElementById('ul')
ul.addEventListener('click', function() {})
這樣我們就實(shí)現(xiàn)了委托,但是有出現(xiàn)了新的問題,如果ul內(nèi)不止li蒸其,那么處于ul內(nèi)的其他元素被點(diǎn)擊時(shí)敏释,事件也被觸發(fā)了!
所以我們需要在觸發(fā)事件前來一個(gè)判斷
ul.addEventListener('click', function(e)
// 檢查事件源e.targe是否為L(zhǎng)i
if (e.target && e.target.nodeName.toUpperCase == "LI") {
// 真正的處理過程在這里
console.log("點(diǎn)擊成功")
}
}
這樣就大功告成了摸袁?很遺憾钥顽,這種情況還存在一個(gè)嚴(yán)重的bug,如果元素在li中呢靠汁?那么事件就不會(huì)觸發(fā)蜂大!比如這樣
<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>
那么該怎么做呢?我們需要再加一個(gè)判斷蝶怔,判斷點(diǎn)擊的元素的父輩元素中有沒有l(wèi)i奶浦,如果有,就繼續(xù)執(zhí)行事件添谊。
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('執(zhí)行回調(diào)函數(shù)')
}
}
后記
我們發(fā)現(xiàn)問題财喳,然后找出方法解決問題。并不代表事件的結(jié)束斩狱,我們所用的方法也許會(huì)帶來其他的原題耳高。多思考,多測(cè)試所踊,不斷完善泌枪。記住,現(xiàn)在得到的永遠(yuǎn)不是最佳答案秕岛。