事件冒泡、事件捕获和事件委托

一、事件冒泡和事件捕获的区别

  • 事件冒泡:目标元素事件先触发,然后父元素事件触发
  • 事件捕获:父元素事件先触发,然后目标元素事件触发

事件执行顺序是:

  • 先事件捕获(从 Windows -> document 依次往下)
  • 再是目标事件处理
  • 最后是事件冒泡

addEventListener() 第三个参数为 false 事件触发顺序是冒泡顺序,true 为捕获顺序,默认为 false(这个冒泡和捕获是说当子元素被点击时,我是先执行还是后执行)。

<div class="parent">
  <div class="child"></div>
</div>
<script>
  window.onload = function() {
    const $ = function(el) {
      return document.querySelector(el);
    };

    // 冒泡:child parent
    $(".parent").addEventListener("click", function() {
        console.log("parent");
    }, false);

    // 捕获:parent child
    $(".parent").addEventListener("click", function() {
      console.log("parent");
    }, true);

    // 目标元素
    $(".child").addEventListener("click", function() {
      console.log("child");
    }, false);
  };
</script>

二、事件委托

事件委托(即事件代理),是利用事件冒泡原理,把事件监听绑定在元素的父级上。当元素被点击时,父级上绑定的点击事件就会被触发,事件触发函数里通过判断 e.target 上的 data-nameclass 等标识来执行不同的逻辑。

优点

  1. 减少事件注册,节省内存。比如,在table上代理所有td的click事件。在ul上代理所有li的click事件。
  2. 简化了dom节点更新时,相应事件的更新。比如不用在新添加的li上绑定click事件。当删除某个li时,不用移解绑上面的click事件。

缺点

  1. 事件委托基于冒泡,对于不冒泡的事件不支持。
  2. 层级过多,冒泡过程中,可能会被某层阻止掉(event.stopPropagation)。
  3. 理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在table上代理td,而不是在document上代理td。
  4. 把所有事件都用代理就可能会出现事件误判。比如,在document中代理了所有button的click事件,另外的人在引用改js时,可能不知道,造成单击button触发了两个click事件。

使用场景

1. 比如我们有个ul,ul里有99个li,我们不用为每个li绑定事件,我们只需要给ul绑定一个事件就可以了。如果li里面有子元素,我们需要使用递归调用:

ul.addEventListener("click", function(e) {
  var target = e.target;
  while (target.nodeName !== "ul") {
    if (target.nodeName.toLocaleLowerCase() == "li") {
      console.log(target.id);
      break;
    }
    target = target.parentNode;
  }
}, false);

2. React的事件都是代理到 document 上的。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章