首先要作的第一件事情就是要先搞清楚什麼是事件委託/綁定,這個東西有什麼用,有什麼優勢和缺點,這樣才能更好的去了解學習相關的知識。html
那就先作第一件事,認識事件綁定,不過說這個以前得先了解一下DOM事件流。node
一、什麼是事件流函數
事件流描述的是從頁面中接收事件的順序。但有意思的是,IE 和 Netscape 開發團隊竟然提出了差
很少是徹底相反的事件流的概念。IE 的事件流是事件冒泡流,而 Netscape Communicator 的事件流是事
件捕獲流。學習
a、IE中的事件流測試
IE 的事件流叫作事件冒泡(event bubbling),即事件開始時由最具體的元素(文檔中嵌套層次最深
的那個節點)接收,而後逐級向上傳播到較爲不具體的節點(也能夠說是由子到父或者說從下到上)。this
若是你單擊了頁面中的 <div> 元素,那麼這個 click 事件會按照以下順序傳播:
(1) <div>
(2) <body>
(3) <html>
(4) documentspa
代碼以下:設計
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Event Bubbling Example</title> 5 </head> 6 <body> 7 <div id="myDiv">Click Me</div> 8 </body> 9 </html>
b、Netscape提出的事件流3d
Netscape Communicator團隊提出的另外一種事件流叫作事件捕獲(event capturing)。事件捕獲的思想
是不太具體的節點應該更早接收到事件,而最具體的節點應該最後接收到事件。事件捕獲的用意在於在
事件到達預約目標以前捕獲它。code
若是仍之前面的 HTML 頁面做爲演示事件捕獲的例子,那麼單擊 <div>元素就會如下列順序觸發 click 事件。
(1) document
(2) <html>
(3) <body>
(4) <div>
「DOM2級事件」規定的事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。首
先發生的是事件捕獲,爲截獲事件提供了機會。而後是實際的目標接收到事件。最後一個階段是冒泡階
段,能夠在這個階段對事件作出響應。
再貼一個很形象的圖片:
二、事件處理程序
a、HTML事件處理程序
某個元素支持的每種事件,均可以使用一個與相應事件處理程序同名的 HTML 特性來指定。
b、 DOM0 級事件處理程序
經過 JavaScript 指定事件處理程序的傳統方式,就是將一個函數賦值給一個事件處理程序屬性
c、DOM2 級事件處理程序
DOM2級事件定義了兩個方法,用於處理指定和刪除事件處理程序的操做: addEventListener()和 removeEventListener()
三、什麼是事件委託/綁定
對「事件處理程序過多」問題的解決方案就是事件委託。事件委託利用了事件冒泡,只指定一個事
件處理程序,就能夠管理某一類型的全部事件。例如, click 事件會一直冒泡到 document 層次。也就
是說,咱們能夠爲整個頁面指定一個 onclick 事件處理程序,而沒必要給每一個可單擊的元素分別添加事
件處理程序。
那事件委託有什麼用呢?
//1.事件未綁定第一個問題 事件覆蓋問題
//沒有加事件綁定時出現的問題
<div style="height:100px; width:100px; background="red"; ">測試</div>
1 var box = document.getElementsByTagName('div')[0]; 2 box.onclick = function() { 3 alert(1); 4 }; 5 box.onclick = function() { 6 alert(2); 7 }; 8 box.onclick = function() { 9 alert(3); // 只有這一個會顯示 前兩個都會被覆蓋掉 10 };
//有加事件綁定時
1 box.addEventListener("click", function() { 2 alert(1) //這裏的每個都會顯示出來 3 }, false) 4 box.addEventListener("click", function() { 5 alert(2) //這裏的每個都會顯示出來 6 }, false) 7 box.addEventListener("click", function() { 8 alert(3) //這裏的每個都會顯示出來 9 }, false)
//2.事件綁定第二個問題 相同函數屏蔽問題
1 box.addEventListener("click",fn, false) 2 box.addEventListener("click",fn, false) 3 function fn(){ 4 alert(1) 5 }
//3.事件綁定第三個問題 傳遞this問題
//沒有事件綁定時的this
1 box.onclick = function() { 2 fn(); 3 }; 4 5 function fn() { 6 alert(this); //window 這裏的this指的仍是window 7 }; 8 9 //有事件綁定時的this 10 box.addEventListener('click', fn, false); 11 12 function fn() { 13 alert(this); //div this的值從上面傳過來了 14 };
//4.事件綁定第三個問題 添加一個事件會被覆蓋或者只執行一次
1 box.onclick = function() { 2 alert(100); 3 }; 4 box.onclick = fn; 5 6 function fn() { 7 alert(200); 8 }; 9 10 box.addEventListener("click", function() { 11 alert(100); 12 }, false) 13 box.addEventListener("click", fn, false) 14 15 function fn() { 16 alert(200); 17 };
//IE中 event對象的獲取
1 box.onclick=function(ev){ 2 alert(ev) //傳統方法IE沒法經過參數獲取ev 3 } 4 box.addEventListener("click",function(ev){ 5 alert(ev) //能夠經過事件綁定來獲取 6 })
最後就是兼容封裝
1 //兼容寫法封裝 2 //添加事件綁定 3 function addEvent(obj, event, fn, bool) { //obj對象 event:事件 fn綁定函數 bool:是否捕獲 4 if (obj.addEventListener) { 5 obj.addEventListener(event, fn, bool); 6 } else { 7 obj.attachEvent('on' + event, fn) 8 } 9 } 10 11 //刪除事件綁定 12 function removeEvent(obj, event, fn, bool) { //obj對象 event:事件 fn綁定函數 13 if (obj.removeEventListener) { 14 obj.removeEventListener(event, fn, bool); 15 } else { 16 obj.detachEvent('on' + event, fn) 17 } 18 }
window.onload = function(){ var oUl = document.getElementById("ul1"); oUl.onclick = function(ev){ var ev = ev || window.event; //event兼容寫法 var target = ev.target || ev.srcElement; //target兼容寫法 if(target.nodeName.toLowerCase() == 'li'){ alert(target.innerHTML); } } }
更加詳細的去參考高級程序設計第13章