javascript中有兩種事件模型:DOM0,DOM2。而對於這兩種的時間模型,我一直不是很是的清楚,如今經過網上查閱資料終於明白了一些。javascript
一. DOM0級事件模型html
DOM0級事件模型是早期的事件模型,全部的瀏覽器都是支持的,並且其實現也是比較簡單。代碼以下:java
<p id = 'click'>click me</p> <script> document.getElementById('click').onclick = function(event){ alert(event.target); } </script>
這種事件模型就是直接在dom對象上註冊事件名稱,這段代碼就是在p標籤上註冊了一個onclick事件,在這個事件函數內部輸出點擊的目標。而解除事件則更加簡單,就是將null複製給事件函數,以下:瀏覽器
document.getElementById('click'_).onclick = null;
由此咱們能夠知道dom0中,一個dom對象只能註冊一個同類型的函數,由於註冊多個同類型的函數的話,就會發生覆蓋,以前註冊的函數就會無效。dom
var click = document.getElementById('click');
click.onclick = function(){
alert('you click the first function');
};
click.onclick = function(){
alert('you click the second function')
}
在這段代碼中,咱們爲dom對象註冊了兩個onclick函數,可是結果是隻執行了第二個註冊的函數,前面所註冊的函數被覆蓋了。函數
二. DOM2級事件模型spa
1. 事件捕獲和事件冒泡(capture,bubble)code
首先,IE8及如下是不支持這種事件模型的。事件捕獲和事件冒泡的機制以下圖:htm
如上圖所示,123表明事件捕獲,4567表明事件冒泡。首先咱們使用下面的代碼:對象
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'> <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div> </div>
假設咱們點擊了ID爲inner的div,那麼此時的事件流程就是,首先執行捕獲階段:document-html-body-div(outer)。而後執行冒泡階段:div(inner)-div(outer)-body-html-document。
2. DOM2級的註冊事件和解除事件
在DOM2級中使用addEventListener和removeEventListener來註冊和解除事件(IE8及以前版本不支持)。這種函數較之以前的方法好處是一個dom對象能夠註冊多個相同類型的事件,不會發生事件的覆蓋,會依次的執行各個事件函數。
addEventListener('事件名稱','事件回調','捕獲/冒泡')。示例以下:
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'> <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div> </div> <script> var click = document.getElementById('inner'); click.addEventListener('click',function(){ alert('click one'); },false); click.addEventListener('click',function(){ alert('click two'); },false); </script>
首先咱們要知道addEventListenr的第一個參數是事件名稱,與DOM0級不一樣的是沒有」on「,另外第三個參數表明捕獲仍是冒泡,true表明捕獲事件,false表明冒泡事件。
而在這段代碼中,咱們爲inner的div註冊了兩個click事件函數,結果是瀏覽器會依次執行這兩個函數。
下面咱們演示如何使用事件流的發生機制。
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'> <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div> </div> <script> var click = document.getElementById('inner'); var clickouter = document.getElementById('outer'); click.addEventListener('click',function(){ alert('inner show'); },true); clickouter.addEventListener('click',function(){ alert('outer show'); },true); </script>
這段代碼,咱們使用了捕獲事件,因爲inner是嵌套在outer中的,因此咱們知道當使用捕獲的時候outer是應該首先捕獲到這個事件的,其次inner才能捕獲到這個事件。那麼結果就是outer首先執行,其次是inner執行。
那麼我把outer的執行時機改成冒泡的階段呢?
alickouter.addEventListener('click',function(){
alert('outer show');
},false);
這種狀況下,就是先執行inner後執行outer了。同理咱們把兩者的事件執行時機都改成冒泡階段的話,依舊是先執行inner後執行outer。那麼還有個問題,就是若是咱們把inner註冊兩個click事件,一個是在捕獲階段,另外一個是在冒泡階段,也就是說把addEventListenter的第三個參數分別設置爲false和true,那麼執行的順序又是怎樣的呢。
<script> var click = document.getElementById('inner'); var clickouter = document.getElementById('outer'); click.addEventListener('click',function(){ alert('capture show'); },true); click.addEventListener('click',function(){ alert('bubble show'); },false); </script>
這種狀況下首先這些的是capture show,其次是bubble show。可是這種結果是與註冊的順序有關係的,先註冊就先執行。由於咱們在看事件捕獲和事件冒泡示意圖,發現最後具體的dom對象是隻有一個的。
那麼 若是咱們給outer和inner都註冊了click事件可是我不但願outer執行怎麼辦呢?這個時候咱們就須要用到stopPropagation函數了,這個函數是用來阻止冒泡,言下之意是讓事件再也不繼續冒泡下去,這樣接下來註冊一樣類型事件的dom對象就不會執行了。好比在自制下拉框的時候,咱們點擊瀏覽器的其餘位置,咱們須要下拉框的options隱藏,這時咱們就要用到stopPropagation了。以下:
<script> var click = document.getElementById('inner'); var clickouter = document.getElementById('outer'); click.addEventListener('click',function(event){ alert('inner show'); event.stopPropagation(); },false); clickouter.addEventListener('click',function(){ alert('outer show'); },false); </script>
正常的狀況下,咱們在不添加stopPropagation函數時,首先應該執行inner,而後執行outer,可是當咱們在inner的事件函數中添加了stopPropagation函數以後,執行完inner的事件函數以後,就不會在執行outer的事件函數了,也能夠理解爲事件冒泡到inner以後就消失了,所以也就不會在執行接下來的事件函數了。
因爲事件捕獲階段沒有能夠阻止事件的函數,因此通常都是設置爲事件冒泡。