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

wwwicbd · 2016年02月24日 · 最后由 fighterleslie 回复于 2016年02月25日 · 2995 次阅读
<!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 更多讨论:

需要 登录 后方可回复, 如果你还没有账号请 注册新账号