JS:事件委托
事件委托
事件流
事件流描述的是從頁面中接收事件的順序。---JS高級程序設計(第3版)
DOM Level 2 Events
規定的事件流有三個階段:①事件捕獲階段、②處於目標階段、③事件冒泡階段事件委托
當需要添加的事件過多時,可以使用事件委托,而事件委托實際上利用了事件冒泡的特性。
使用事件委托還需了解事件對象(
event
):在觸發DOM上的某個事件時,會產生一個事件對象event
,這個對象中包含著所有與事件有關的信息。在此僅需知道在
DOM
標準中,event
擁有一個target
屬性表示事件目標。event.target
是一個觸發事件的對象的引用。它與event.currentTarget
具體
Event
詳情可以查看MDN:Event
如果你想要在大量子元素中單擊任何一個都可以運行一段代碼,您可以將事件監聽器設置在其父節點上,並將事件監聽器氣泡的影響設置為每個子節點,而不是每個子節點單獨設置事件監聽器。(mdn)
以下面的html代碼為例:
<ul id="list"> <li id="one">do something</li> <li id="two">do something</li> <li id="three">do something</li> </ul>
當需求是單擊上面每個
li
標簽都會執行各種操作時,使用事件委托是較好的選擇。// bad (逐個 li 添加事件) let item1 = document.getElementById(‘one‘); let item2 = document.getElementById(‘two‘); let item3 = document.getElementById(‘three‘); item1.addEventListener(‘click‘, function(){...}, false); item1.addEventListener(‘click‘, function(){...}, false); item1.addEventListener(‘click‘, function(){...}, false); // event delegation (事件委托) let list = document.getElementById(‘list‘); list.addEventListener(‘click‘, function(e){ if (e.target && e.target.nodeName == ‘LI‘) { switch (e.target.id) { case ‘one‘: do something; break; case ‘two‘: do something; break; case ‘three‘: do something; break; } } }, false);
註意:當
li
標簽被如p
、div
等撐滿時,點擊的target
為p
標簽而不是li
標簽會導致無法正確執行click
事件。以下面的html代碼為例:
<ul id="list"> <li id="one">do something</li> <li id="two">do something</li> <!-- 這裏的 li 裏面有個 p 標簽 --> <li id="three"><p>do something</p></li> </ul>
這樣的情況可以使用遞歸 or 循環來處理,畢竟事件委托是利用事件冒泡的特性。
//遞歸 let list = document.getElementById(‘list‘); list.addEventListener(‘click‘, function(e){ eventDelegation(e.target); }, false); function eventDelegation(target) { if (target && target.nodeName == ‘LI‘) { switch (target.id) { case ‘one‘: do something; return; case ‘two‘: do something; return; case ‘three‘: do something; return; } } return eventDelegation(target.parentNode); }
使用事件委托的優點
a.減少DOM操作,使事件處理時間減少。
b.減少內存空間的使用,提升性能。
因為在JavaScript中,每個函數都是對象,對象越多,占用的內存也就越多,合理使用事件委托可以減少內存的占用。
註意事項
比較適合使用事件委托的事件:
click
、mousedown
、mouseup
等,而如mouseout
、mouseover
等則不太適合使用事件委托(雖然mouseout
這些事件也冒泡,但通常需要確定元素的位置,所以不太推薦使用事件委托)。另外不會冒泡的事件是不適合使用事件委托的。
JS:事件委托