为何捕获事件和冒泡事件执行了两次?

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>事件冒泡</title>
  <style type="text/css">
  #child{
    background: red;
    width:50px;
    height:50px;
  }
  #father{
    width:100px;
    height:100px;
    background:green;
  }
  #grandparent{
    width:150px;
    height:150px;
    background:black;
    margin:100px auto 0;
  }
  </style>
</head>
<body>
  <div id='grandparent'>
    <div id='father'>
      <div id='child'></div>
    </div>
  </div>
</body>
<script type="text/javascript">
  var grandparent = document.getElementById("grandparent");
  var parent = document.getElementById("father");
  var child = document.getElementById('child');
  var html = document.getElementsByTagName("html")[0];
  var body = document.body;
  grandparent.addEventListener("click",function () {
    console.log("I am capturing grandparent");
  },true);
  grandparent.addEventListener("click",function () {
    console.log("I am grandparent");
  },false);
  parent.addEventListener("click",function() {
    console.log("I am capturing parent");
  },true);
   parent.addEventListener("click",function() {
    console.log("I am parent");
  },false);
   child.addEventListener("click",function() {
    console.log("I am capturing child");
  },true);
  child.addEventListener("click",function() {
    console.log("I am child");
  },false);
  body.addEventListener("click",function() {
    console.log("I am capturing body");
  },true);  
  body.addEventListener("click",function() {
    console.log("I am body");
  },false);
  html.addEventListener("click",function() {
    console.log("I am capturing html");
  },true);
  html.addEventListener("click",function() {
    console.log("I am html");
  },false);
  document.addEventListener("click",function() {
    console.log("I am capturing document");
  },true);
  document.addEventListener("click",function() {
    console.log("I am document");
  },false);
  window.addEventListener("click",function() {
    console.log("I am capturing window");
  },true);
  window.addEventListener("click",function() {
    console.log("I am window");
  },false);
  parent.addEventListener("click",function() {
    console.log("I am capturing parent");
  },true);
   parent.addEventListener("click",function() {
    console.log("I am parent");
  },false);
</script>
</html>

注意:我将

  parent.addEventListener("click",function() {
    console.log("I am capturing parent");
  },true);
   parent.addEventListener("click",function() {
    console.log("I am parent");
  },false);
  

上面的两行代码重复了两次,一次在中间,一次在末尾。

点击緑色的div,得到下面的结果:

test.html:75 I am capturing window
test.html:69 I am capturing document
test.html:63 I am capturing html
test.html:57 I am capturing body
test.html:39 I am capturing grandparent
test.html:45 I am capturing parent
test.html:48 I am parent
test.html:81 I am capturing parent
test.html:84 I am parent
test.html:42 I am grandparent
test.html:60 I am body
test.html:66 I am html
test.html:72 I am document
test.html:78 I am window

为何结果不是
test.html:75 I am capturing window
test.html:69 I am capturing document
test.html:63 I am capturing html
test.html:57 I am capturing body
test.html:39 I am capturing grandparent
test.html:45 I am capturing parent
test.html:48 I am parent
test.html:42 I am grandparent
test.html:60 I am body
test.html:66 I am html
test.html:72 I am document
test.html:78 I am window

或者

test.html:75 I am capturing window
test.html:69 I am capturing document
test.html:63 I am capturing html
test.html:57 I am capturing body
test.html:39 I am capturing grandparent
test.html:45 I am capturing parent
test.html:81 I am capturing parent
test.html:48 I am parent
test.html:84 I am parent
test.html:42 I am grandparent
test.html:60 I am body
test.html:66 I am html
test.html:72 I am document
test.html:78 I am window

请解释?

阅读 2.5k
4 个回答
  1. 事件触发流程是捕获 -> 目标 -> 冒泡,不管你是否监听或者监听几次,事件都会触发,你监听只是绑定了事件的回调函数,并不影响事件的触发。所以监听2次必然会执行两次
  2. 由于测试的代码测试的是点击目标,在目标阶段可以理解为捕获和冒泡是一致的,所以先绑定的先执行,后绑定的后执行。如果你把代码测试到点击元素的父元素,会得到期望的结果

找了半天才发现,哥们你给 parent 添加了两次事件,能不执行两次吗!

事件监听是两次。所以事件执行也是两次。

应该是click事件处理函数的队列里的冒泡和捕获是放在一起的,所以你添加的顺序是,捕获,冒泡,捕获,冒泡,所以它执行的时候就是按这个顺序执行。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏