傳統的事件處理javascript
事件委託就是在一個頁面上使用一個事件來管理多種類型的事件。這並非一個新的想法,但對於把握性能來講卻很重要。一般狀況,你會在web應用程序中看到這樣的代碼:html
document.getElementById("help-btn").onclick = function(event){ openHelp(); };
document.getElementById("save-btn").onclick = function(event){ saveDocument(); };
document.getElementById("undo-btn").onclick = function(event){ undoChanges(); };java
這種傳統的編碼方式給每一個元素分配單獨的事件處理方法。對於交互少的站點來講,這樣作是能夠的。然而,對於大型的wen應用程序,當存在大量的事件處理的時候,就會顯得反應遲鈍。這裏要關注的不是速度問題,而是內存佔用問題。若是有數百個交互,DOM元素和JavaScript代碼就會有數百個關聯。web應用須要佔用的內存越多,它的響應速度就越慢。事件委託能將這個問題減少。
web
事件冒泡及捕獲瀏覽器
要不是事件的下面這些屬性,事件委託將成爲可能。早期的web開發,瀏覽器廠商很難回答一個哲學上的問題:當你在頁面上的一個區域點擊時,你真正感興趣的是哪一個元素。這個問題帶來了交互的定義。在一個元素的界限內點擊,顯得有點含糊。畢竟,在一個元素上的點擊同時也發生在另外一個元素的界限內。例如單擊一個按鈕。你實際上點擊了按鈕區域、body元素的區域以及html元素的區域。函數
伴隨着這個問題,兩種主流的瀏覽器Netscape和IE有不一樣的解決方案。Netscape定義了一種叫作事件捕獲的處理方法,事件首先發生在DOM樹的最高層對象(document)而後往最深層的元素傳播。在圖例中,事件捕獲首先發生在document上,而後是html元素,body元素,最後是button元素。性能
IE的處理方法正好相反。他們定義了一種叫事件冒泡的方法。事件冒泡認爲事件促發的最深層元素首先接收事件。而後是它的父元素,依次向上,知道document對象最終接收到事件。儘管相對於html元素來講,document沒有獨立的視覺表現,他仍然是html元素的父元素而且事件能冒泡到document元素。因此圖例中噢噢那個button元素先接收事件,而後是body、html最後是document。編碼
在定義DOM的時候,W3C顯然看到了這兩種方案各自的優勢,因此DOM Level 2的事件規範中同時定義了這兩種方案。首先document元素得到事件,而後捕獲階段向與事件最相關的元素傳播,當事件被此元素捕獲後,再冒泡到document元素。addEventListener()方法接受三個參數:事件名,事件處理函數,一個用於指定事件在捕獲階段處理仍是在冒泡階段處理的布爾值。大部分的web開發者都會使用false做爲第三個參數這樣就跟IE中的attachEvent()同樣了。spa
//bubbling phase handler
document.addEventListener("click", handleClick, false);
//capturing phase handler
document.addEventListener("click", handleClick, true);orm
經過冒泡實現事件委託
事件委託的關鍵就是在經過冒泡方式實如今最高層(一般是document)處理事件。不是全部的事件都支持冒泡,可是鼠標和鍵盤事件支持,而且這也是你所關心的。回顧下前面的例子,你能夠經過在document上分配一個事件來處理全部的單擊事件,只須要經過區別節點來決定處理事件的方法。
document.onclick = function(event){
//IE doesn't pass in the event object
event = event || window.event;
//IE uses srcElement as the target
var target = event.target || event.srcElement;
switch(target.id){
case "help-btn":
openHelp();
break;
case "save-btn":
saveDocument();
break;
case "undo-btn":
undoChanges();
break;
//others?
}
};
使用事件委託,數個事件處理函數可使用一個函數來管理。全部的單擊事件被委託給一個合適的函數來處理。一樣,mousedown, mouseup, mousemove, mouseover, mouseout, dblclick, keyup, keydown, 和keypress事件也能夠這樣處理。可是,在事件委託中mouseover和mouseout的處理方法是不一樣的,當鼠標從一個元素移動到它的子元素內的時候,被認爲是"out"。
注意:你也可使用事件捕獲來完成事件委託,但這隻能用在支持事件捕獲的非IE瀏覽器中。
優勢
事件委託對於web應用程序的性能有以下幾個優勢:
1.須要管理的函數變少了
2.佔用的內存少了
3.javascript代碼和Dom結構之間的關聯更少了
4.在改變DOM結構中的innerHTML時,不須要改動事件處理函數
從傳統的事件處理方法轉向事件委託提升了大型web應用的性能。正由於它如此的重要,一些相似於YUI、jQuey的javascript庫也開始將事件委託應用在它們的核心接口中。實現事件委託是很輕鬆的,卻能帶來性能上很大的提升。尤爲表如今你將數十個事件處理函數整合到一個函數裏。試一下事件委託,你就不會再使用傳統的事件處理方法了。
bind() 是直接綁定在元素上,而 live() 是經過冒泡的方式來綁定到元素上。舉兩個應用場景來講明他們的存在:
第1、有一個按鈕,你想要用他來在點擊的時候經過 AJAX 提交 form 的請求。
由於這裏只有一個按鈕,只綁定一次,你並不須要冒泡這種更費力費資源的方式來冒泡到 document 再指定這個元素。
第2、在一個有 20個以上,甚至更多個 li 的 ul 列表中,要讓每個 li 點擊的時候都去觸發相應函數的時候。
若是給每一個 li 都綁定一個 click 事件,這樣是否是很蛋疼?這時經過 live()(固然更好是用 delegate() 這樣的方法,能夠指定一個離 li 更近的父節點),其實只在 document 上綁定一次 click() 事件,你省了 19 次綁定。這是多省內存的事。對吧?