JavaScript-淺談DOM事件流

什麼是事件?(敲黑板)

事件,就是文檔或瀏覽器窗口發生的一些特定的交互瞬間。(by 《JavaScript高級程序設計》)
好比鼠標點擊,雙擊,滾動條滑動...javascript

什麼是事件流?

先來看一個簡單的例子:html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div class="main">
        <div class="btn-wrap">
            <button id="btn">點擊</button>
        </div>
    <div>
</body>
</html>

這時候咱們點擊btn的同時,也能夠視爲同時點擊了btn的容器元素,甚至單擊了整個頁面。
事件流指的是從頁面接收事件的順序。
關於事件流,IE和Netscape提出了差很少相反的概念,IE提出的就是廣爲人知的事件冒泡流,而Netscape提出的則是事件捕獲流java

1. 事件冒泡

事件冒泡,即事件開始時由最具體的元素接收,如上面例子中的btn,而後逐漸向上級傳播到較爲不具體的節點。DOM2級事件規定addEventListener方法的第三個參數設爲false,表示事件在冒泡階段觸發。瀏覽器

注:使用頻繁的事件委託實際上也是利用了事件冒泡。spa

仍是相同的DOM結構爲例:設計

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div class="main">
        <div class="btn-wrap">
            <button id="btn">點擊</button>
        </div>
    <div>
    <script type="text/javascript">
        var btn=document.querySelector("#btn"),
            btnWrap=document.querySelector(".btn-wrap"),
            main=document.querySelector(".main"),
            body=document.querySelector("body"),
            html=document.querySelector("html");
            btn.addEventListener("click",function(){
                console.log("你點擊了ID爲btn的button元素!");
            },false);
            btnWrap.addEventListener("click",function(){
                console.log("你點擊了class爲btn-wrap的DIV元素!");
            },false);
            main.addEventListener("click",function(){
                console.log("你點擊了class爲main的DIV元素!");
            },false);
            body.addEventListener("click",function(){
                console.log("你點擊了body元素!");
            },false);
            html.addEventListener("click",function(){
                console.log("你點擊了html元素!");
            },false);
            document.addEventListener("click",function(){
                console.log("你點擊了document對象!");
            },false);
    </script>
</body>
</html>

若是咱們點擊btn,那麼這個click事件的傳播順序以下:
圖片描述code

也就是,click事件首先在btn元素上觸發,而這個元素就是咱們單擊的元素,而後click事件沿DOM樹向上傳播,在每一級的節點都會發生,直至傳播到document對象。
全部現代瀏覽器都支持事件冒泡。htm

2. 事件捕獲

事件捕獲,即事件從不太肯定的節點接收,而後向下傳播到最具體的節點,事件捕獲的用意在於在事件到達預期目標以前捕獲它。DOM2級事件規定addEventListener方法的第三個參數設爲true,表示事件在捕獲階段觸發。
仍是相同的DOM結構爲例:
將參數改成true對象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div class="main">
        <div class="btn-wrap">
            <button id="btn">點擊</button>
        </div>
    <div>
    <script type="text/javascript">
        var btn=document.querySelector("#btn"),
            btnWrap=document.querySelector(".btn-wrap"),
            main=document.querySelector(".main"),
            body=document.querySelector("body"),
            html=document.querySelector("html");
            btn.addEventListener("click",function(){
                console.log("你點擊了ID爲btn的button元素!");
            },true);
            btnWrap.addEventListener("click",function(){
                console.log("你點擊了class爲btn-wrap的DIV元素!");
            },true);
            main.addEventListener("click",function(){
                console.log("你點擊了class爲main的DIV元素!");
            },true);
            body.addEventListener("click",function(){
                console.log("你點擊了body元素!");
            },true);
            html.addEventListener("click",function(){
                console.log("你點擊了html元素!");
            },true);
            document.addEventListener("click",function(){
                console.log("你點擊了document對象!");
            },true);
    </script>
</body>
</html>

若是咱們點擊btn,那麼這個click事件的傳播順序以下:
圖片描述事件

在事件捕獲過程當中,document對象首先接收到click事件,而後事件沿着DOM樹依次向下傳播。
目前支持事件捕獲流的瀏覽器有:IE9,Safari,Chrome,Opera,Firefox。
因爲老版本瀏覽器不支持事件捕獲,建議你們更多的是用事件冒泡,在有特殊須要時再使用事件捕獲。

3. DOM事件流

根據DOM2級事件規定,事件流應該包括三個階段,事件捕獲階段,處於目標階段和事件冒泡階段。
仍是相同的DOM結構爲例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div class="main">
        <div class="btn-wrap">
            <button id="btn">點擊</button>
        </div>
    <div>
    <script type="text/javascript">
        var btn=document.querySelector("#btn"),
            btnWrap=document.querySelector(".btn-wrap"),
            main=document.querySelector(".main"),
            body=document.querySelector("body"),
            html=document.querySelector("html");
            //冒泡
            btn.addEventListener("click",function(){
                console.log("你點擊了ID爲btn的button元素!");
            },false);
            btnWrap.addEventListener("click",function(){
                console.log("你點擊了class爲btn-wrap的DIV元素!");
            },false);
            main.addEventListener("click",function(){
                console.log("你點擊了class爲main的DIV元素!");
            },false);
            body.addEventListener("click",function(){
                console.log("你點擊了body元素!");
            },false);
            html.addEventListener("click",function(){
                console.log("你點擊了html元素!");
            },false);
            document.addEventListener("click",function(){
                console.log("你點擊了document對象!");
            },false);

            //捕獲
            btn.addEventListener("click",function(){
                console.log("你點擊了ID爲btn的button元素!");
            },true);
            btnWrap.addEventListener("click",function(){
                console.log("你點擊了class爲btn-wrap的DIV元素!");
            },true);
            main.addEventListener("click",function(){
                console.log("你點擊了class爲main的DIV元素!");
            },true);
            body.addEventListener("click",function(){
                console.log("你點擊了body元素!");
            },true);
            html.addEventListener("click",function(){
                console.log("你點擊了html元素!");
            },true);
            document.addEventListener("click",function(){
                console.log("你點擊了document對象!");
            },true);
    </script>
</body>
</html>

若是咱們點擊btn,那麼這個click事件的傳播順序以下:
圖片描述

在DOM事件流中,實際的目標btn不會接收到事件。這意味着在捕獲階段,事件從document到btn-wrap就中止了,下一階段是「處於目標」階段,因而事件在btn上發生,而後冒泡階段發生,事件又傳播迴文檔。

注:多數支持DOM事件流的瀏覽器都實現了一種特定行爲,即便DOM2級事件規範明確要求捕獲階段不會涉及目標階段,IE9,Safari,Chrome,Firefox,Opera9.5及更高版本都會在事件捕獲階段觸發事件對象上的事件,這也是上圖btn被觸發兩次的緣由。
IE9,Safari,Chrome,Firefox,Opera都支持DOM事件流,IE8及更早版本不支持DOM事件流。

本文知識點大多來自《JavaScript高級程序設計》一書,博主在這裏也是作一次總結,鞏固一下相關知識,同時也但願沒接觸過事件流的童鞋們,有一個大概的概念。

相關文章
相關標籤/搜索