1、事件流瀏覽器
1. 事件流: 函數
事件流描述的是從頁面中接收事件的順序。IE 的事件流是事件冒泡流,Netscape 的事件流是事件捕獲流。this
2. 事件冒泡流:spa
IE 的事件流叫事件冒泡,即事件開始時由最具體的元素(文檔中嵌套層次最深的那個節點)接收,而後逐級向上傳播到較爲不具體的節點(文檔)。3d
若點擊了頁面中的某個div,則該click事件會按如圖所示的順序傳播code
click首先在 div 元素上發生,而這個元素是咱們點擊的元素。以後,click事件沿DOM樹向上傳播,在每一級節點上都會發生,直至傳播到document對象。對象
3. 事件捕獲流blog
Netscape 的事件流叫事件捕獲,事件捕獲的思想是不太具體的節點應該更早接收到事件,而最具體的節點應該最後接收到事件。事件捕獲的用意在於在事件到達預約目標以前捕獲它。事件
在事件捕獲過程當中,document對象首先接收到click事件,而後事件沿DOM樹依次向下,一直傳播到事件的具體目標,即 div 元素。捕獲的順序如圖所示ip
4. DOM 事件流
‘DOM2級事件’規定事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。首先發生的是事件捕獲,爲截獲事件提供了機會。而後是實際的目標接收到事件。最後是冒泡階段,在這個階段對事件做出響應。
2、事件處理程序
響應某個事件的函數就叫事件處理程序(事件偵聽器)。事件處理程序的名字以‘on’開頭,因此click的事件處理程序是onclick,load的事件處理程序是onload。爲事件制定處理程序有以下幾種方式:
(1)HTML 事件處理程序
1 <input type="button" onclick="alert('hello world')"> 2 <input type="button" onclick="handle()"> 3 <script> 4 function handle() { 5 alert('hello world'); 6 } 7 </script>
(2)DOM0級事件處理程序
1 var btn = document.getElementById('btn'); 2 btn.onclick = function() { 3 alert('hello world'); 4 }
使用DOM0 級方法指定的事件處理程序被認爲是元素的方法。所以,此時事件處理程序實在元素的做用域中運行,即程序中的this引用當前元素。例如:
1 var btn = document.getElementById('btn'); 2 btn.onclick = function() { 3 alert(this.id); //'btn' 4 }
在事件處理程序中能夠經過 this 訪問元素的任何屬性和方法,以這種方式添加的事件處理程序會在事件流的冒泡階段被處理。
刪除經過 DOM0 級方法指定的事件處理程序,可將事件處理程序的屬性值設爲 null。
1 btn.onclick = null;
(3)DOM2 級事件處理程序
DOM2 級事件有兩個方法用於處理指定和刪除事件處理程序的操做: addEventListener() 和 removeEventListener()。
全部的 DOM 節點都包含這兩個方法,而且都接收3個參數:要處理的事件名、做爲事件處理程序的函數和一個布爾值。這個布爾值參數若是是 true,表示在捕獲階段調用事件處理程序;若是是 false,表示在冒泡階段調用事件處理程序。
通常地,都是把事件處理程序添加都事件流的冒泡階段,能夠極大限度地兼容各類瀏覽器。最好只在須要在事件到達目標以前捕獲它的時候將事件處理程序添加到捕獲階段。除非特殊須要,不建議在事件捕獲階段註冊事件處理程序。
1 var btn = document.getElementById('btn'); 2 btn.addEventListener('click', function() { 3 alert('hello world'); 4 }, false); 5 // 或者 6 function handle() { 7 alert('hello world'); 8 } 9 btn.addEventListener('click', handle, false);
使用 DOM2 級方法添加事件處理程序的好處在於能夠添加多個事件處理程序,而且兩個事件處理程序會按照添加他們的順序依次出發。例如:
1 btn.addEventListener('click', function() { 2 alert('hello world'); 3 }, false); 4 btn.addEventListener('click', function() { 5 alert(this.id); 6 }, false); 7 //'hello world' 8 //'btn'
經過 addEventListener() 添加的事件處理程序只能經過 removeEventListener() 移除,移除時傳入的參數與添加處理程序使用的參數相同,這意味着經過addEventListener() 添加的匿名函數將沒法移除。例如:
1 btn.removeEventListener('click', function() { 2 alert('hello world'); 3 }, false); 4 // 無效
正確的用法是
1 function handler() { 2 alert('hello world'); 3 } 4 btn.addEventListener('click', handler, false); 5 btn.removeEventListener('click', handler, false);
(4)IE事件處理程序
在 IE 中提供了兩個方法 attachEvent() 和 detachEvent()用於添加事件處理程序,都接受兩個參數:事件處理程序名稱和事件處理程序函數。因爲 IE8 及更早版本只支持事件冒泡,所以addtachEvent 添加的事件處理程序都會被添加到冒泡階段。用法以下:
1 var btn = document.getElementById('btn'); 2 btn.attachEvent('onclick', function() { 3 alert('hello world'); 4 })
在使用 attachEvent() 的時候,事件處理程序是運行在全局做用域下,所以 this 指向的是 window 對象。
1 btn.attachEvent('onclick', function() { 2 alert(this == window); // true 3 })
attachEvent() 也能夠爲一個元素添加多個事件處理程序,只不過觸發的順序與添加的順序相反。
1 btn.attachEvent('onclick', function() { 2 alert(this.id); 3 }) 4 btn.attachEvent('onclick', function() { 5 alert('hello world'); 6 }) 7 // 'hello world' 8 // 'btn'
detachEvent 用於移除事件處理程序,須要的參數與 attachEvent() 添加時的同樣,這也意味着添加的匿名函數不能被移除,正確用法以下:
function handler() { 2 alert('hello world'); 3 } 4 btn.attachEvent('onclick', handler); 5 btn.detachEvent('onclick', handler);
3、跨瀏覽器的事件處理程序
1 var EventUtil = { 2 addHandler: function(element, type, handler) { 3 if(element.addEventListener) { 4 element.addEventListener(type, handler, false); 5 } 6 else if(element.attachEvent) { 7 element.attachEvent('on' + type, handler); 8 } 9 else { 10 element['on' + type] = handler; 11 } 12 }, 13 removeHandler: function(element, type, handler) { 14 if(element.removeEventListener) { 15 element.removeEventListener(type, handler, false); 16 } 17 else if(element.detachEvent) { 18 element.detachEvent('on' + type, handler); 19 } 20 else { 21 element['on' + type] = null; 22 } 23 } 24 } 25 // 使用方法 26 var btn = document.getElementById('btn'); 27 function handlerFn() { 28 alert('hello world'); 29 } 30 EventUtil.addHandler(btn, click, handlerFn); 31 EventUtil.removeHandler(btn, click, handlerFn);