事件委托,又稱事件代理,把原本需要綁定在子元素的響應事件委托給父元素(即綁定在父元素上),讓父元素擔當事件監聽的職務。原理是dom元素的事件冒泡。
舉個通俗的例子:比如一個宿舍的同學同時快遞到了,一種方法就是他們一個個去領取,還有一種方法就是把這件事情委托給宿舍長,讓一個人出去拿好所有快遞,然后再根據收件人一 一分發給每個宿舍同學;
在這里,取快遞就是一個事件,每個同學指的是需要響應事件的 DOM 元素,而出去統一領取快遞的宿舍長就是代理的元素,所以真正綁定事件的是這個元素,按照收件人分發快遞的過程就是在事件執行中,
需要判斷當前響應的事件應該匹配到被代理元素中的哪一個或者哪幾個。
dom事件流,一個事件觸發后,會在子元素和父元素之間傳播(propagation)。這種傳播分成三個階段。
(1)捕獲階段:從window對象傳導到目標節點(上層傳到底層)稱為“捕獲階段”(capture phase),捕獲階段不會響應任何事件;
(2)目標階段:在目標節點上觸發,稱為“目標階段”
(3)冒泡階段:從目標節點傳導回window對象(從底層傳回上層),稱為“冒泡階段”(bubbling phase)。事件代理即是利用事件冒泡的機制把里層所需要響應的事件綁定到外層。
事件委托的優點:
【1】可以大量節省內存占用,減少事件注冊,比如在ul上代理所有li的click事件就非常棒
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
// ...... 代表中間還有未知數個 li
如上面代碼所示,如果給每個li列表項都綁定一個函數,那對內存的消耗是非常大的,因此較好的解決辦法就是將li元素的點擊事件綁定到它的父元素ul身上,執行事件的時候再去匹配判斷目標元素。
【2】可以實現當新增子對象時無需再次對其綁定(動態綁定事件)
假設上述的例子中列表項li就幾個,我們給每個列表項都綁定了事件;
在很多時候,我們需要通過 AJAX 或者用戶操作動態的增加或者刪除列表項li元素,那么在每一次改變的時候都需要重新給新增的元素綁定事件,給即將刪去的元素解綁事件;
如果用了事件委托就沒有這種麻煩了,因為事件是綁定在父層的,和目標元素的增減是沒有關系的,執行到目標元素是在真正響應執行事件函數的過程中去匹配的;所以使用事件在動態綁定事件的情況下是可以減少很多重復工作的。
使用事件委托注意事項:使用“事件委托”時,並不是說把事件委托給的元素越靠近頂層就越好。事件冒泡的過程也需要耗時,越靠近頂層,事件的”事件傳播鏈”越長,也就越耗時。如果DOM嵌套結構很深,事件冒泡通過大量祖先元素會導致性能損失。
2.怎么阻止默認動作?
有一些html元素默認的行為,比如說a標簽,點擊后有跳轉動作;form表單中的submit類型的input有一個默認提交跳轉事件;reset類型的input有重置表單行為。
如果你想阻止這些瀏覽器默認行為,JavaScript為你提供了方法。
如下代碼:
var $a = document.getElementsByTagName("a")[0];
$a.onclick = function(e){
alert("跳轉動作被我阻止了")
e.preventDefault();
//return false;//也可以
}
默認事件沒有了。
既然return false 和 e.preventDefault()都是一樣的效果,那它們有區別嗎?當然有。
僅僅是在HTML事件屬性 和 DOM0級事件處理方法中,才能通過返回 return false 的形式組織事件宿主的默認行為。
3.怎么阻止冒泡事件
function stopBubble(e){
if(e&&e.stopPropagation){//非IE
e.stopPropagation();
}
else{//IE
window.event.cancelBubble=true;
}
}