事件委托

在JavaScript中,事件委托Event delegation是一種事件的響應(yīng)機(jī)制,當(dāng)需要監(jiān)聽(tīng)不存在的元素或是動(dòng)態(tài)生成的元素時(shí),可以考慮事件委托。

事件委托得益于事件冒泡(有關(guān)事件冒泡可以參考事件冒泡與事件捕獲),當(dāng)監(jiān)聽(tīng)子元素時(shí),事件冒泡會(huì)通過(guò)目標(biāo)元素向上傳遞到父級(jí),直到document,如果子元素不確定或者動(dòng)態(tài)生成,可以通過(guò)監(jiān)聽(tīng)父元素來(lái)取代監(jiān)聽(tīng)子元素。

舉個(gè)例子:
假設(shè)頁(yè)面從存在一個(gè)ul,其子元素動(dòng)態(tài)生成.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>事件委托</title>
</head>
<body>
  <button>點(diǎn)擊</button>
  <ol></ol>
  <script>
    let btn = document.getElementsByTagName('button')[0]
    let ol = document.getElementsByTagName('ol')[0]

    btn.addEventListener('click',function(){
        let li = document.createElement('li')
        let number = parseInt(Math.random() * 100, 10)
        li.textContent=number
        ol.appendChild(li)
    })
  
  <script>
</body>
</html>

當(dāng)點(diǎn)擊按鈕時(shí),ol列表中動(dòng)態(tài)創(chuàng)建li,如果給li添加click事件,當(dāng)li被點(diǎn)擊時(shí),li本身被刪除,那么可以這樣實(shí)現(xiàn)

 btn.addEventListener('click',function(){
      let li = document.createElement('li')
      let number = parseInt(Math.random() * 100, 10)
      li.textContent=number
      ol.appendChild(li)
      li.addEventListener('click',function(){
         li.remove();
      })
 })

但是這樣就會(huì)使得給每個(gè)li都添加了click事件(或者其他的事件),而頁(yè)面中的li是不確定有多少的,如果頁(yè)面中生成很多的li,那么就會(huì)造成內(nèi)存占用過(guò)多,因此我們可以使用事件委托來(lái)解決這個(gè)問(wèn)題。

/*  
li.addEventListener('click',function(){
     li.remove();
})   
*/
 ol.addEventListener('click',function(e){
     let ele = e.target
     if(ele.tagName==='LI'){
        ele.remove()
     }
  })

在這個(gè)例子中,通過(guò)給父級(jí)而非子集添加事件,當(dāng)事件被拋到更上層的父節(jié)點(diǎn)的時(shí)候,我們通過(guò)檢查事件的目標(biāo)對(duì)象target來(lái)判斷并獲取事件源li,當(dāng)子節(jié)點(diǎn)被點(diǎn)擊的時(shí)候,click事件會(huì)從子節(jié)點(diǎn)開(kāi)始向上冒泡。父節(jié)點(diǎn)捕獲到事件之后,通過(guò)判斷e.target.nodeName來(lái)判斷是否為我們需要處理的節(jié)點(diǎn)。并且通過(guò)e.target拿到了被點(diǎn)擊的Li節(jié)點(diǎn)。從而可以獲取到相應(yīng)的信息,并作處理。

但是當(dāng)li中有其他的標(biāo)簽時(shí)如span標(biāo)簽(或是其他的標(biāo)簽),直接使用上述方法就會(huì)導(dǎo)致事件無(wú)法被正確觸發(fā)。

 btn.addEventListener('click',function(){
      let li = document.createElement('li')
      let span = document.createElement('span')
      let number = parseInt(Math.random() * 100, 10)

      span.textContent=number
      li.appendChild(span)
      ol.appendChild(li)
      ol.addEventListener('click',function(e){
         let ele = e.target
         if(ele.tagName==='LI'){
            ele.remove()
         }
      }) 
 })

此時(shí),當(dāng)點(diǎn)擊span時(shí),li并未被刪除,點(diǎn)擊spanli之間的部分li才會(huì)被刪除,試想當(dāng)子元素li中有多層嵌套時(shí),就會(huì)導(dǎo)致事件無(wú)法被正確觸發(fā),因此我們需要對(duì)li進(jìn)行判斷,判斷點(diǎn)擊的是否是ol下的li,否則就繼續(xù)查找,直到查找到li。

 btn.addEventListener('click',function(){
      let li = document.createElement('li')
      let span = document.createElement('span')
      let number = parseInt(Math.random() * 100, 10)

      span.textContent=number
      li.appendChild(span)
      ol.appendChild(li)
      ol.addEventListener('click',function(e){
         let ele = e.target
         while(ele.tagName!=='LI'){
              if(ele===ol){
                 ele=null; break;
               }
               ele=ele.parentNode
          }
          ele && ele.remove()
      }) 
 })

此時(shí)不論li嵌套多少層,liclick事件都會(huì)被正確觸發(fā)。

事件委托可以通過(guò)監(jiān)聽(tīng)父級(jí)來(lái)達(dá)到監(jiān)聽(tīng)子級(jí)的效果,減少了監(jiān)聽(tīng)器的數(shù)量,使用內(nèi)存也相對(duì)減少。當(dāng)在一些難以追蹤的情況下,從DOM從刪除的元素仍保留「記憶」(即泄露),這些泄露的「記憶」通常與事件綁定聯(lián)系在一起,使用事件委托,可以隨意的對(duì)子元素進(jìn)行事件綁定而不用擔(dān)心忘記解綁它們的監(jiān)聽(tīng)器。

參考:

  1. What is DOM Event delegation?
  2. How JavaScript Event Delegation Works
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.背景介紹 1.1什么是事件委托? 事件委托還有一個(gè)名字叫事件代理,JavaScript高級(jí)程序設(shè)計(jì)上講:事件委...
    我叫于搞吧閱讀 1,713評(píng)論 4 9
  • 一直以來(lái),對(duì)js的一些概念還是不清晰的,很多都沒(méi)有搞明白,今天無(wú)意間在群里見(jiàn)他們提起事件委托,所以查找了一些資料,...
    蝴蝶結(jié)199007閱讀 324評(píng)論 1 3
  • 大家好,我是IT修真院成都分院第07期學(xué)員,一枚正直善良的web程序員。 一、小課堂簡(jiǎn)述JS中的事件委托 1.背景...
    120De丶L閱讀 380評(píng)論 0 0
  • 鏈接地址:http://www.cnblogs.com/liugang-vip/p/5616484.htmlhtt...
    青春前行閱讀 863評(píng)論 0 0
  • 下午到新鄉(xiāng)了,打掃完衛(wèi)生鋪好床整好衣服收拾完該收拾的,去破街吃了飯,買(mǎi)了沒(méi)帶的東西,太累了...住在外的第一天晚上...
    達(dá)浪打啦閱讀 149評(píng)論 0 0

友情鏈接更多精彩內(nèi)容