很多情況下都可能使用到事件委托讶迁,那么對(duì)于一個(gè)使用者來說,為什么要使用事件委托?又是否正確的使用了事件委托吻贿?這里我想簡(jiǎn)單的說一下我對(duì)使用原生JS實(shí)現(xiàn)事件委托的理解,有不準(zhǔn)確的地方望指教哑子。
概述
事件委托有哪些好處舅列,才會(huì)被在編程中大量的使用呢?
那么就得先說說事件的一些性能和使用的問題:
- 綁定事件越多卧蜓,瀏覽器內(nèi)存占用越大帐要,嚴(yán)重影響性能。
- 部分瀏覽器移除元素時(shí)弥奸,綁定的事件并沒有被及時(shí)移除榨惠,導(dǎo)致的內(nèi)存泄漏,嚴(yán)重影響性能
事件委托的基礎(chǔ)
- 事件的冒泡盛霎,所以才可以在父元素來監(jiān)聽子元素觸發(fā)的事件赠橙。
- DOM的遍歷,一個(gè)父級(jí)元素包含的子元素過多愤炸,那么當(dāng)一個(gè)事件被觸發(fā)時(shí)期揪,是否觸發(fā)了某一種類型的元素呢?
//這是老師為教學(xué)造的一個(gè)事件委托的小輪子示例
let dom = {
on: function(element, eventType, selector, fn) {
element.addEventListener(eventType, e => {
let el = e.target
while (!el.matches(selector)) {
if (element === el) {
el = null
break
}
el = el.parentNode
}
el && fn.call(el, e, el)
})
return element
}
一個(gè)簡(jiǎn)單的事件委托
只是使用文字描述规个,是無法很好的理解事件委托的凤薛,那么這里我們來看一個(gè)例子:
注:假設(shè)只支持標(biāo)準(zhǔn)瀏覽器,不兼容IE的低版本
我現(xiàn)在使用原生的JS诞仓,來實(shí)現(xiàn)一個(gè)簡(jiǎn)單的事件委托
<ul>
<li><span>選項(xiàng)1</span></li>
<p><span>這行是p</span></p>
<li>選項(xiàng)2</li>
<li>選項(xiàng)3</li>
<li>選項(xiàng)4</li>
</ul>
如果我想在點(diǎn)擊每一行的li元素后就打印出來一個(gè)數(shù)字缤苫,假設(shè)li增加到100行,是不是要寫100個(gè)監(jiān)聽事件呢墅拭,顯然榨馁,這種笨拙的做法是不會(huì)被天生驕傲與懶惰的程序員們拒絕的,如果li元素里還增加了其它元素帜矾,那又會(huì)出現(xiàn)不能觸發(fā)的bug,這與初設(shè)是相差甚遠(yuǎn)的翼虫。這樣事件委托就是需要出現(xiàn)的時(shí)候了,我們只需要往上監(jiān)聽父元素屡萤,而對(duì)于滿足條件的子元素珍剑,只需要觸發(fā)父元素,就會(huì)觸發(fā)滿足條件判斷的所有子元素死陆。
var ul = document.querySelector('ul')
ul.addEventListener('click',function(e){
var el = e.target
while(el.tagName !== 'LI'){
el = el.parentNode
if(el === ul){
el = null;
break;
}
}
if(el){
console.log('我點(diǎn)擊了ul里的li')
}else{
console.log('我點(diǎn)擊的不是ul里的li')
}
})
運(yùn)行JS后招拙,可以看到唧瘾,點(diǎn)擊黃色區(qū)域內(nèi)外的兩行內(nèi)容,在控制臺(tái)console出來的內(nèi)容是不一樣的别凤,這就是典型的事件委托簡(jiǎn)單示例饰序。
由此示例再一次證實(shí),在必需用事件委托的地方规哪,一定存在影響性能的一個(gè)前提: 元素中求豫,綁定事件委托的次數(shù)太多,嚴(yán)重影響性能诉稍;
事件委托由底層級(jí)元素向上遍歷直到監(jiān)聽層級(jí)的父元素蝠嘉,如果返回null,就跳出循環(huán)杯巨,否則遍歷層級(jí)越多蚤告,同樣影響性能。所以事件委托綁定在合理的低層級(jí)元素上同樣也很重要服爷。