DOM事件流中的冒泡和捕獲

這是本人的第一篇文章,歡迎你們多多批評指正!javascript

DOM2級事件中addEventListener的執行機制,多個addEventListener同時添加時的執行前後規律:css

W3C的DOM事件觸發分爲三個階段:
1.事件捕獲階段:即由最頂層元素(通常是從window元素開始,有的瀏覽器是從document開始,至於其中的差異我稍後會更新)開始,逐次進入dom內部,最後到達目標元素,依次執行綁定在其上的事件;
2.處於目標階段:檢測機制到達目標元素,按事件註冊順序執行綁定在目標元素上的事件;
3.事件冒泡階段:從目標元素出發,向外層元素冒泡,最後到達頂層(window或document),依次執行綁定再其上的事件。html

在addEventListener中,利用第三個參數控制其是從哪一個階段開始,「true」是從捕獲階段開始,而「false」則是跳過捕獲階段,從冒泡階段開始。 java

下面是一個簡單的例子:瀏覽器

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>事件流</title>
        <style type="text/css">
            #outer {
                width: 400px;
                height: 400px;
                background: #ccc;
            }
            #inner {
                width: 100px;
                height: 100px;
                background: #aaa;
            }
        </style>
    </head>
    <script type="text/javascript">
        window.onload = function() {
            var outer = document.getElementById("outer");
            var inner = document.getElementById('inner');

            outer.addEventListener("click", function() {
                alert("outer捕獲");
            }, true);

            inner.addEventListener("click", function() {
                alert("inner捕獲");
            }, true);

            outer.addEventListener("click",function() {
                alert("outer冒泡");
            }, false)
        }
    </script>
    <body>
        <div id="outer">
            <div id="inner"></div>
        </div>
    </body>
</html>

在這個例子裏,若是咱們點擊內層元素inner,那麼處於捕獲階段的「outer捕獲」最早彈出,接下來是目標元素"inner捕獲"彈出,最後是處於冒泡階段的"outer冒泡"彈出,即:「outer捕獲」-->"inner捕獲"-->"outer冒泡"。 即便在代碼裏變換三個綁定事件的順序,只要點擊的是inner,這個執行順序就不會變。dom

那麼問題來了,若是咱們點擊的是外層outer的話呢?函數

要明白這個問題,咱們必須明確一點:目標事件在哪一層,事件流就在哪一層迴流,即便在outer事件下還有許多子孫節點,事件流都不會在outer以後往內流,此時,inner上的事件不會被觸發,所以在這段代碼中,只會彈出「outer捕獲」和"outer冒泡"。code

那麼哪一個先彈呢?因爲此時事件處於第二階段,即「處於目標階段」,彈出順序取決的也再也不是捕獲或冒泡,而是誰在代碼中先註冊,所以,在這段代碼中,彈出的是:「outer捕獲」→"outer冒泡"。htm

綜上所述,事件在DOM中的執行順序爲:外層捕獲事件→內層捕獲事件→先註冊的目標事件→後註冊的目標事件→內層冒泡事件→外層冒泡事件事件

讓咱們加深理解,看下面這個例子:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>事件流</title>
        <style type="text/css">
            #box {
                width: 600px;
                height: 600px;
                background: yellow;
            }
            
            #outer {
                width: 400px;
                height: 400px;
                background: #ccc;
            }
            
            #inner {
                width: 100px;
                height: 100px;
                background: #aaa;
            }
        </style>
    </head>
    <script type="text/javascript">
        window.onload = function() {
            var outer = document.getElementById("outer");
            var inner = document.getElementById('inner');
            var oBox = document.getElementById('box');

            oBox.addEventListener("click", function() {
                alert('oBox冒泡');
            }, false)

            oBox.addEventListener("click", function() {
                alert('oBox捕獲');
            }, true)

            outer.addEventListener("click", function() {
                alert("outer捕獲");
            }, true);

            outer.addEventListener("click", function() {
                alert("outer冒泡");
            }, false);

            
            inner.addEventListener("click", function() {
                alert('inner冒泡')
            }, false);
            
            inner.addEventListener("click", function() {
                alert("inner捕獲");
            }, true);
            /*綜上所述,事件在DOM中的執行順序爲:外層捕獲事件→內層捕獲事件→先註冊的目標事件→後註冊的目標事件→內層冒泡事件→外層冒泡事件*/
        }
    </script>

    <body>
        <div id="box">
            <div id="outer">
                <div id="inner"></div>
            </div>
        </div>
    </body>

</html>

在這段代碼裏,點擊inner,box上的捕獲事件最早執行,而後是outer上的捕獲事件,而後是inner上先註冊的事件,而後是inner上後註冊的事件,最後是box上的冒泡事件 彈出順序爲:'oBox捕獲'→"outer捕獲"→'inner冒泡'→"inner捕獲"→"outer冒泡"→"oBox冒泡"。

補充一點,在ie8-中,因爲addEventLister不起做用,咱們使用attachEvent方法來綁定事件,此時在第二階段,也就是處於目標階段,若是目標元素上綁定了兩個事件,那麼其執行順序和addEventLister相反:誰後註冊誰先執行。

若是dom0級事件和dom2級事件同時存在,那執行順序會是怎樣呢?

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>事件流</title>
    <style>
        #box {
            width: 600px;
            height: 600px;
            background: yellow;
        }
            
        #outer {
            width: 400px;
            height: 400px;
            background: #ccc;
        }
            
        #inner {
            width: 100px;
            height: 100px;
            background: #aaa;
        }
    </style>
</head>
<body>
    <div id="box">
        <div id="outer">
            <div id="inner"></div>
        </div>
    </div>
</body>

<script type="text/javascript">
    window.onload = function () {

        var outer = document.getElementById("outer");
        var inner = document.getElementById('inner');
        var oBox = document.getElementById('box');

        oBox.addEventListener("click", function () {
            alert('oBox-Dom2冒泡');
        }, false);

        oBox.addEventListener("click", function () {
            alert('oBox-Dom2捕獲');
        }, true);
        outer.onclick = function(){
            alert("outer-dom0 click! ");
        }
        outer.addEventListener("click", function () {
            alert("outer-Dom2冒泡");
        }, false);
        
         
        outer.addEventListener("click", function () {
            alert("outer-Dom2捕獲");
        }, true);
    
        inner.addEventListener("click", function () {
            alert('inner-Dom2冒泡');
        }, false);

        inner.addEventListener("click", function () {
            alert("inner-Dom2捕獲");
        }, true);
    }
</script>

上面的例子中,我將outer的div在捕獲階段和冒泡階段都綁定了點擊事件,同時還在綁定了dom0級的點擊事件處理函數,這時若是咱們點擊inner,咱們會發現,事件的執行順序是這樣的oBox-Dom2捕獲--> outer-Dom2捕獲 --> inner-Dom2冒泡 --> inner-Dom2捕獲 -->outer-dom0 click!-->outer-Dom2冒泡 --> oBox-Dom2冒泡。

由此咱們能夠得出一個結論:當綁定dom0級事件元素不是目標元素時,那麼綁定dom0級事件的處理是在冒泡階段處理並按事件註冊的前後順序執行(W3C先註冊的先執行) ,若是綁定dom0級事件的元素是目標元素時,則不管是捕獲階段綁定的處理函數仍是冒泡階段綁定的處理函數以及dom0級事件處理函數,他們的執行順序都是按照註冊的順序執行(W3C先註冊的先執行) 。

相關文章
相關標籤/搜索