JavaScript 关于事件捕获与事件冒泡的疑问

wwwicbd · February 24, 2016 · Last by fighterleslie replied at February 25, 2016 · 2983 hits
<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="div1">
        <button id="btn">按钮</button>
    </div>
<script>
    var btn = document.getElementById("btn");
    var div1 = document.getElementById("div1");

    //事件冒泡
    btn.onclick = function(){
        console.debug("冒泡1.Click btn");
    }
    div1.onclick = function(){
        console.debug("冒泡1.5 Click div1");
    }
    document.body.onclick = function(){
        console.debug("冒泡2.Click Body");
    }
    document.onclick = function(){
        console.debug("冒泡3.Click document");
    }
    window.onclick = function(){
        console.debug("冒泡4.Click window");
    }

    //事件捕获
    window.addEventListener("click",function(){
        console.debug("捕获4.Click window");
    },true);
    document.addEventListener("click",function(){
        console.debug("捕获3.Click document");
    },true);
    document.body.addEventListener("click",function(){
        console.debug("捕获2.Click body");
    },true);
    div1.addEventListener("click",function(){
        console.debug("捕获1.5 Click div1");
    },true);
    btn.addEventListener("click",function(){
        console.debug("捕获1.Click btn");
    },true);
</script>

</body>
</html>

Chrome console 结果

疑问:图中『冒泡 1』与『捕获 1』的顺序为什么是反的?

事件传播三阶段:

  • capture phase(事件捕获)
  • target phase(处于目标)
  • bubbling phase(事件冒泡)

在 target phase,event handler 被调用的顺序不再遵循先捕获,后冒泡的原则,而是严格按照 event handler 注册的顺序

在例子中,

btn.onclick = function(){
    console.debug("冒泡1.Click btn");
}

先于

btn.addEventListener("click",function(){
    console.debug("捕获1.Click btn");
},true);

注册,故而先执行。

要改变二者的执行顺序,只需要改变两段源码的顺序即可。

W3C 规范

Next, the implementation must determine the current target's candidate event listeners. This must be the list of all event listeners that have been registered on the current target in their order of registration. [HTML5] defines the ordering of listeners registered through event handler attributes. Once determined, the candidate event listeners must not be changed. Adding or removing listeners does not affect the current target's candidate event listeners.

StackOverflow 更多讨论:

You need to Sign in before reply, if you don't have an account, please Sign up first.