JS事件模型

討論的主要是兩個事件模型:IE事件模型與DOM事件模型

IE內核瀏覽器的事件模型是冒泡型事件(沒有捕獲事件過程),事件句柄的觸發順序是從ChildNode到ParentNode。 

 <div id="ancestor"> 

       <button id="child"> 

           Open the console and click me 

       </button> 

</div> 

以上的HTML代碼在IE內核下,事件是這樣傳播的:{

1、Button#child; 
2、div#ancestor; 
3、Body; 
4、Document 

} 


DOM標準的瀏覽器事件是:捕獲事件和冒泡事件。

捕獲事件過程:{

1、Window 
2、Document 
3、Body 
4、Div#ancestor 
5、Button#child 

}

冒泡事件過程:{

6、Div#ancestor 
7、Body 
8、Document 
9、Window 

}

當開發者在一個元素上註冊了事件後,這個事件的響應順序是從window(最頂層)開始一級一級的向下傳播,然後到了該元素後事件捕獲過程結束,事件開如冒泡,一級一級向父層元素冒泡(請注意第6步)。

當然,開發者可以很輕鬆的決定DOM標準的瀏覽器中的事件需要在哪個傳播過程觸發。


事件的註冊機制:

DOM標準的瀏覽器事件註冊方法是通過addEventListener方法註冊,而IE內核的瀏覽器則是通過attachEvent方法註冊。 
這兩個方法的區別:
addEventListener方法帶有三個參數,分別是:eventType、handler、useCapture。 
eventType不帶有on字符串; 
handler參數是一個事件句柄,這個函數或方法帶有一個事件對象參數; 
useCapture參數決定了事件句柄觸發在哪種事件傳播階段,如果useCapture爲true則爲捕獲階段,反之則爲冒泡階段。 


繼續看演示: 

var ancestorHandler = function (e){ 

//...... 

 }, 

 childHandler = function (e){ 

//...... 

}; 

 document.querySelector('#ancestor').addEventListener('click',ancestorHandler,false);//注意第三個參數 ,註冊了一個在冒泡階段觸發的事件句柄

 document.querySelector('#child').addEventListener('click',childHandler,true);//注意第三個參數 ,註冊了一個在捕獲階段的事件句柄
 
當用戶在這個DIV元素上點擊時,事件的執行順序是childHandler、ancestorHandler。 

原因:按鈕的事件是在捕獲階段觸發的,也就是從上到下,而DIV的事件是註冊在冒泡階段,也就是點擊了這個按鈕開始從這個按鈕的位置往上冒泡。

 

阻止事件的冒泡:

DOM事件對象提供了stopPropagation方法用於阻止事件流。 

var ancestorHandler = function (e){ 
  //...... 
}, 
childHandler = function (e){ 
  e.stopPropagation(); 
  //...... 
}; 

以上代碼在childHandler函數中添加了e.stopPropagation()代碼片段,它將阻止事件流,事件流包括捕獲階段及冒泡階段的事件流。 


再修改上面的代碼如下: 

var ancestorHandler = function (e){ 
  //...... 
}, 
childHandler = function (e){ 
  //...... 
}; 
document.querySelector('#ancestor').addEventListener('click',ancestorHandler,true);//注意第三個參數 
document.querySelector('#child').addEventListener('click',childHandler,true);//注意第三個參數 

以上的代碼產生的結果是:用戶在DIV元素上單擊時,將會依次觸發ancestorHandler、childHandler函數,爲什麼?因爲我們將div#ancestor的事件註冊到捕獲階段了,也就是從上至下。當然了我們還可以阻止childHandler方法的執行。 
1 var ancestorHandler = function (e){ 
2   e.stopPropagation(); 
3   //...... 
4 }, 
5 childHandler = function (e){ 
6   //...... 
7 }; 

以上代碼將阻止按鈕的事件觸發。當用戶點擊了DIV的區域,僅僅觸發ancestorHandler函數,因爲阻止了事件流。 


IE內核的瀏覽器中是如何註冊事件的。IE內核提供了attachEvent方法爲元素註冊事件,注意該方法與DOM的addEventListener方法區別很大!該方法帶有兩個參數:{

eventType 事件類型,請注意這個參數與addEventListener的eventType的區別,它必須帶有on; 

handler 事件句柄 ,請注意attachEvent沒有提供事件捕獲階段的參數,IE內核的事件都是發生在冒泡階段! 

}

var ancestorHandler = function (e){ 
  //...... 
}, 
childHandler = function (e){ 
  //...... 
}; 
document.getElementById('ancestor').attachEvent('onclick',ancestorHandler);//注意沒有第三個參數 
document.getElementById('child').attachEvent('onclick',childHandler);//注意沒有第三個參數 

以上代碼在IE中將爲DIV元素和按鈕元素註冊了不同的事件。 


另外還有一些注意事項: 

1、DOM標準的addEventListener方法執行事件的順序是按照事件註冊的順序執行的。而attachEvent方法則相反–後註冊的事件先觖發,先註冊的事件後觸發。 
2、DOM標準的瀏覽器文本節點也會冒泡,而IE內核的瀏覽器文本節點不會冒泡。 
3、DOM標準的瀏覽器事件對象與IE內核的瀏覽器事件不同(具體請參閱http://www.quirksmode.org/js/introevents.html)。 
4、DOM標準的瀏覽器事件卸載方式與IE內核的事件卸載方式不同。 
1 object.removeEventListener(eventType,handler,useCapture);//DOM標準的事件卸載方式 
2 object.detachEvent(eventType,handler);//IE內核的事件卸載方式 

在DOM標準的事件卸載方式中需要注意的是:事件捕獲的參數。如果你的事件是註冊在捕獲階段,則卸載事件時,必須將其指定爲捕獲階段(true),否則無法卸載;如果你的事件註冊在註冊在冒泡階段,則必須將其指定爲冒泡階段(false),否則同樣無法卸載!
發佈了38 篇原創文章 · 獲贊 24 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章