首先,講一下爲什麼會有事件流模型。舉個簡單的例子來說,當你看着紙上一組同心圓的時候,你拿着筆點着同心圓裏最小的那個圓的時候,是不是也可以說你也在點着這組同心圓的所有圓?顯然是可以說的。
所以,當你點擊頁面上的一個button,你是不是也在點擊着包含這個button的父級元素?同樣,是的。這便是爲什麼會有事件流以及事件流模型。
事件流
事件流有兩種:一種是微軟公司提出的冒泡事件流,一種是網景公司提出捕獲事件流。它們定義的事件傳播方向恰恰相反。
- 事件冒泡(Event Capturing): 是一種從下往上的傳播方式。事件最開始由最具體的元素(也就是DOM最底層的子節點), 然後逐漸向上傳播到最不具體的那個節點(也就是DOM中最高層的父節點)。
- 事件捕獲(Event Bubbling): 是一種從上到下的傳播方式。事件最開始由不太具體的節點最早接受事件, 而最具體的節點最後接受事件。
例如:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="myDiv">Click me!</div>
</body>
</html>
在冒泡型事件流中click事件傳播順序爲div -> body -> html -> document
在捕獲型事件流中click事件傳播順序爲document -> html -> body -> div
之前,微軟公司的IE系列瀏覽器主張冒泡型事件處理,網景公司的Netscape系列瀏覽器主張捕獲型,誰也說服不了誰,之後W3C組織制定了DOM標準事件流,但可惜的是網景公司並未撐到DOM標準制定就被收購了,但它的捕獲事件流的思想卻被借鑑了下來。
DOM事件流:
DOM標準採用捕獲+冒泡。兩種事件流都會觸發DOM的所有對象,從document對象開始,也在document對象結束。
DOM標準規定事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。
事件捕獲階段:實際目標(div)在捕獲階段不會接收事件。也就是在捕獲階段,事件從document到html再到body就停止了。上圖中爲1~3.
處於目標階段:事件在div上發生並處理。但是事件處理會被看成是冒泡階段的一部分。
冒泡階段:事件又傳播回document
事件流模型
現在常用事件流模型的可以說就是2種:DOM0 模型,DOM2模型。(有些說是3種,HTML事件處理程序、DOM0 模型、DOM2模型,雖然說HTML事件處理程序不存在瀏覽器的兼容性問題,但個人不推薦使用,可自行了解)
DOM 0 模型:
如要給btn按鈕添加點擊事件處理程序
<input type="button" id="btn">
在js代碼區添加事件處理程序和綁定關係
var btn = document.getElementById("btn");
btn.onclick = function showMessage(){
alert("hello world");
}
如果要移除該點擊事件處理程序
btn.onclick = null;
DOM 0模型並不是W3C組織制定的標準,但是由於在W3C組織制定標準之前,這種方式廣被各種瀏覽器所採用,到現在各種瀏覽器也都支持,所以就被保留了下來。
說明:DOM 0模型不存在瀏覽器兼容性的問題,也就是說,它被各種瀏覽器支持,可跨瀏覽器使用。
注意:通過DOM 0方法添加的事件,無法控制是冒泡事件流還是捕獲事件流,但是現今流行的瀏覽器中(safari、IE、opera、chrome、Firefox)都把其在冒泡事件流階段處理。
DOM 2 模型:
如要給btn按鈕添加點擊事件處理程序
<input type="button" id="btn">
js區添加事件處理程序和綁定關係
var btn= document.getElementById("btn");
btn.addEventListener("click", function () {
alert("innerCircle的click事件在捕獲階段被觸發");
},true);
btn.addEventListener("click", function () {
alert("innerCircle的click事件在冒泡階段被觸發");
},false);
事件綁定監聽函數的方式 : addEventListener(eventType, handler, useCapture).
當useCapture取值false爲冒泡階段調用事件處理程序;當useCapture取值true爲捕獲階段調用事件處理程序。
移除事件的方式:removeEventListener(eventType, handler, useCapture)
說明:DOM 2 模型並未被IE9以下版本支持即 IE(6,7,8)不支持DOM 2 註冊和移除事件的方式,且只支持冒泡事件流,不支持DOM事件流。
在IE(6,7,8)版本中,註冊事件和移除事件的寫法是:
var btn3 = document.getElementById("btn3");
btn3.attachEvent("onclick", showMessage);//註冊事件
btn3.detachEvent("onclick", showMessage);//移除事件
function showMessage(){
alert("hello world");
}
但是IE 9及以上版本(IE 10 ,IE11,IE edge)支持DOM 事件流且支持DOM2註冊和移除事件的方式。
所以,我們可以按照對DOM2的支持把瀏覽器分爲兩類:IE(6,7,8)和 其它瀏覽器。
因此jquery等這些js庫就封裝了跨瀏覽器的事件處理方式。
總結
如果同時出現DOM0和DOM2事件處理程序,那麼不同瀏覽器處理它們的優先級會怎樣呢?
chrome/opera/safari等webkit內核的瀏覽器:DOM2級 DOM0級
firefox瀏覽器和IE瀏覽器(指IE9及以上版本)會將DOM0級事件優先調用:DOM0級 DOM2級