全面解析javascript事件流模型以及各事件流模型在瀏覽器中的兼容性情況

首先,講一下爲什麼會有事件流模型。舉個簡單的例子來說,當你看着紙上一組同心圓的時候,你拿着筆點着同心圓裏最小的那個圓的時候,是不是也可以說你也在點着這組同心圓的所有圓?顯然是可以說的。

所以,當你點擊頁面上的一個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級

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章