事件冒泡、事件捕獲和事件委託

一、事件冒泡和事件捕獲的區別

  • 事件冒泡:目標元素事件先觸發,然後父元素事件觸發
  • 事件捕獲:父元素事件先觸發,然後目標元素事件觸發

事件執行順序是:

  • 先事件捕獲(從 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 上的。

 

 

 

 

 

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