1. 程式人生 > >JS:事件委托

JS:事件委托

dom操作 引用 .get ... 使用 分享圖片 listen 減少 false

事件委托

  1. 事件流

    事件流描述的是從頁面中接收事件的順序。---JS高級程序設計(第3版)

    DOM Level 2 Events規定的事件流有三個階段:①事件捕獲階段、②處於目標階段、③事件冒泡階段

    技術分享圖片

  2. 事件委托

    當需要添加的事件過多時,可以使用事件委托,而事件委托實際上利用了事件冒泡的特性。

    使用事件委托還需了解事件對象(event):在觸發DOM上的某個事件時,會產生一個事件對象event,這個對象中包含著所有與事件有關的信息。

    在此僅需知道在DOM標準中,event擁有一個target屬性表示事件目標。

    event.target是一個觸發事件的對象的引用。它與event.currentTarget

    不同, 當事件處理程序在事件的冒泡或捕獲階段被調用時。(mdn)

    具體Event詳情可以查看MDN:Event


    如果你想要在大量子元素中單擊任何一個都可以運行一段代碼,您可以將事件監聽器設置在其父節點上,並將事件監聽器氣泡的影響設置為每個子節點,而不是每個子節點單獨設置事件監聽器。(mdn)

    以下面的html代碼為例:

    <ul id="list">
        <li id="one">do something</li>
        <li id="two">do something</li>
        <li id="three">do something</li>
    </ul>

    當需求是單擊上面每個li標簽都會執行各種操作時,使用事件委托是較好的選擇。

    // bad (逐個 li 添加事件)
    let item1 = document.getElementById(‘one‘);
    let item2 = document.getElementById(‘two‘);
    let item3 = document.getElementById(‘three‘);
    
    item1.addEventListener(‘click‘, function(){...}, false);
    item1.addEventListener(‘click‘, function(){...}, false);
    item1.addEventListener(‘click‘, function(){...}, false);
    
    // event delegation (事件委托)
    let list = document.getElementById(‘list‘);
    list.addEventListener(‘click‘, function(e){
        if (e.target && e.target.nodeName == ‘LI‘) {
            switch (e.target.id) {
              case ‘one‘:
                do something;
                break;
    
              case ‘two‘:
                do something;
                break;
    
              case ‘three‘:
                do something;
                break;
            }
          }
    }, false);

    註意:當li標簽被如pdiv等撐滿時,點擊的targetp標簽而不是li標簽會導致無法正確執行click事件。

    以下面的html代碼為例:

    <ul id="list">
        <li id="one">do something</li>
        <li id="two">do something</li>
        <!-- 這裏的 li 裏面有個 p 標簽 -->
        <li id="three"><p>do something</p></li>
      </ul>

    這樣的情況可以使用遞歸 or 循環來處理,畢竟事件委托是利用事件冒泡的特性。

    //遞歸
    let list = document.getElementById(‘list‘);
    list.addEventListener(‘click‘, function(e){
     eventDelegation(e.target);
    }, false);
    
    function eventDelegation(target) {
     if (target && target.nodeName == ‘LI‘) {
            switch (target.id) {
              case ‘one‘:
                do something;
                return;
    
              case ‘two‘:
                do something;
                return;
    
              case ‘three‘:
                do something;
                return;
            }
        }
        return eventDelegation(target.parentNode);
    }
  3. 使用事件委托的優點

    a.減少DOM操作,使事件處理時間減少。
    b.減少內存空間的使用,提升性能。

    因為在JavaScript中,每個函數都是對象,對象越多,占用的內存也就越多,合理使用事件委托可以減少內存的占用。

  4. 註意事項

    比較適合使用事件委托的事件:clickmousedownmouseup等,而如mouseoutmouseover等則不太適合使用事件委托(雖然mouseout這些事件也冒泡,但通常需要確定元素的位置,所以不太推薦使用事件委托)。

    另外不會冒泡的事件是不適合使用事件委托的。

JS:事件委托