前言:這是筆者學習以後本身的理解與整理。若是有錯誤或者疑問的地方,請你們指正,我會持續更新!javascript
當瀏覽器發展到第四代時(IE4及Netscape4),瀏覽器開發團隊遇到了一個頗有意思的問題:頁面的哪一部分會擁有某個特定的事件?想象畫在一張紙上的一組同心圓。若是把手指放在圓心上,那麼手指指向的不是一個圓,而是紙上的全部圓。java
兩家公司的瀏覽器開發團隊在看待瀏覽器事件方面仍是一致的。若是單擊了某個按鈕,他們都認爲單擊事件不只僅發生在按鈕上,甚至也單擊了整個頁面。web
但有意思的是,IE 和 Netscape 開發團隊竟然提出了差很少是徹底相反的事件流的概念。IE 的事件流是事件冒泡流,而 Netscape 的事件流是事件捕獲流。chrome
事件流又稱爲事件傳播,描述的是從頁面中接收事件的順序。DOM2 級事件規定的事件流包括三個階段:事件捕獲階段(capture phase)、處於目標階段(target phase)和事件冒泡階段(bubbling phase)。編程
首先發生的是事件捕獲,爲截獲事件提供了機會。而後是實際的目標接收到事件,最後一個階段是冒泡階段,能夠在這個階段對事件作出響應。瀏覽器
默認是在冒泡階段對事件作出響應。函數
IE 的事件流叫作事件冒泡(event bubbling),即事件開始時由最具體的元素(文檔中嵌套層次最深的那個節點)接收,而後逐級向上傳播到 window 對象;學習
全部現代瀏覽器都支持事件冒泡,但在具體實如今仍是有一些差異。IE九、Firefox、Chrome、Safari將事件一直冒泡到 window 對象;this
事件捕獲的思想是 window 對象應該更早接收到事件,而最具體的節點應該最後接收到事件。事件捕獲的用意在於在事件到達預約目標以前就捕獲它;spa
addEventListener() 方法中的第三個參數是指在冒泡階段仍是捕獲階段處理事件處理程序,設置爲 true 時,即爲捕獲階段,默認爲 false 冒泡階段;
某個元素支持的每種事件,均可以使用一個與相應事件處理程序同名的 HTML 特性來指定。這個特性的值應該是可以執行的 javascript 代碼;
在事件處理程序函數內部,this值等於事件的目標元素;
缺點1:由於用戶可能會有HTML元素一出如今頁面上時就觸發相應的事件,但當時的事件處理程序有可能尚不具有執行條件,就會報錯;
缺點2:客戶端編程的通用風格是保持 HTML 內容和 javaScript 行爲分離,因此應該避免使用 HTML 事件處理程序屬性,由於這些屬性直接混合了 javascript 和 HTML,且不易擴展;
經過 javascript 指定事件處理程序的傳統方式,就是將一個函數賦值給一個事件處理程序屬性。這種爲事件處理程序賦值的方法是在第四代Web瀏覽器中出現的,並且至今仍然爲全部現代瀏覽器所支持。緣由一是簡單,二是具備跨瀏覽器的優點。
每一個元素都有本身的事件處理程序屬性,這些屬性一般所有小寫,將這種屬性的值設置爲一個函數,就能夠指定事件處理程序。
以DOM0級方式添加的事件處理程序會在事件流的冒泡階段被處理;
能夠經過將事件處理程序屬性設置爲 null 來刪除事件處理程序;
缺點:DOM0級事件處理程序的缺點是圍繞着每一個事件目標對於每種事件類型只能添加一個事件處理程序。
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> var oBox = document.getElementById('box'); oBox.onclick = function(){ this.innerHTML += 'DOM0級事件處理程序'; } </script>
DOM2級事件處理程序定義了兩個方法用於處理指定和刪除事件處理程序的操做:addEventListener() 和 removeEventListener()。IE8及如下瀏覽器不支持DOM2級事件處理程序。
使用DOM2級事件處理程序的好處是能夠添加多個事件處理程序,並按照他們添加的順序觸發;
<div id="box" style="height:200px;width:200px;background-color:pink;"></div> <script> var oBox = document.getElementById('box'); oBox.addEventListener('click',function(){ this.innerHTML += '使用DOM2級事件處理程序的好處是能夠添加多個事件處理程序<br/>'; }); oBox.addEventListener('click',function(){ this.innerHTML += '並按照他們添加的順序觸發,第三個參數默認爲false,因此是事件冒泡的順序'; }); </script>
全部DOM節點中都包含這兩個方法,而且它們都接受3個參數:要處理的事件名、做爲事件處理程序的函數和一個布爾值。
最後的布爾值參數若是是 true,表示在捕獲階段調用事件處理程序;若是是 false,表示在冒泡階段調用事件處理程序。若最後的布爾值不填寫,則默認爲 false。
<div id="box" style="height:200px;width:200px;background-color:pink;"> <div id="child" style="height: 100px;width: 100px;background-color: green;"></div> </div> <script> var oBox = document.getElementById('box'); var oChild = document.getElementById('child'); oBox.addEventListener('click',function(){ console.log('事件捕獲順序 先oBox'); },true); oChild.addEventListener('click',function(){ console.log('事件捕獲順序 後oChild'); },true); </script>
若最後的布爾值不填寫,則和 false 效果同樣。
<script> var oBox = document.getElementById('box'); var oChild = document.getElementById('child'); oBox.addEventListener('click',function(){ console.log('事件冒泡順序 後oBox'); }); oChild.addEventListener('click',function(){ console.log('事件冒泡順序 先oChild'); }); </script>
經過 addEventListener() 添加的事件處理程序只能使用 removeEventListener() 來移除,移除時傳入的參數與添加處理程序時使用的參數相同。addEventListener() 添加的匿名函數將沒法移除;
<div id="box" style="height:200px;width:200px;background-color:pink;"></div> <script> var oBox = document.getElementById('box'); oBox.addEventListener("click",function(){ this.innerHTML += 'removeEventListener()沒法移除匿名函數'; },false); oBox.removeEventListener('click',function(){ this.innerHTML += 'removeEventListener()沒法移除匿名函數'; },false); </script>
IE實現了與DOM中相似的兩個方法:attachEvent() 和 detachEvent()。這兩個方法接受相同的兩個參數:事件處理程序名稱與事件處理程序函數。因爲IE8及如下瀏覽器只支持事件冒泡,因此經過 attachEvent() 添加的事件處理程序都會被添加到事件冒泡階段;
attachEvent() 方法的第一個參數是"onclick",而非DOM的 addEventListener()方法中的"click";
與其餘三個事件處理程序不一樣,IE事件處理程序的 this 指向 window,而非被綁定事件的元素;
使用 attachEvent() 方法添加的事件處理程序的觸發順序是有區別的。IE九、10瀏覽器是按正序執行的,而IE8及如下瀏覽器則是按倒序執行的;
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> var oBox = document.getElementById('box'); oBox.attachEvent('onclick',function(){ this.innerHTML += 'attachEvent()方法的第一個參數是"onclick"'; //與其餘三個事件處理程序不一樣,IE事件處理程序的this指向window,而非被綁定事件的元素 console.log(this);//window }) </script>
使用 attachEvent() 添加的事件能夠經過 detachEvent() 來移除,條件是必須提供相同的參數。與DOM2級事件處理程序同樣,這也意味着添加的匿名函數將不能被移除。不過,只要可以將對相同函數的引用傳給 detachEvent(),就能夠移除相應的事件處理程序。
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> var oBox = document.getElementById('box'); oBox.attachEvent("onclick",function(){ box.innerHTML += '與DOM2級事件處理程序同樣,attachEvent添加的匿名函數將不能被移除'; },false); oBox.detachEvent('onclick',function(){ box.innerHTML += '與DOM2級事件處理程序同樣,attachEvent添加的匿名函數將不能被移除'; },false); </script>
若是同時出現 HTML 事件處理程序和 DOM0 級事件處理程序,DOM0 級會覆蓋 HTML 事件處理程序;
chrome/opera/safari等 webkit 內核的瀏覽器會按照事件處理程序出現的順序來排列,因此結果爲:DOM2級 DOM0級
firefox 瀏覽器和 IE 瀏覽器會將 DOM0 級事件優先調用,因此 firefox 和 IE11 瀏覽器結果爲:DOM0級 DOM2級
IE九、10瀏覽器結果爲:DOM0級 DOM2級 IE
IE8及如下瀏覽器結果爲:DOM0級 IE