事件委托

在JavaScript中,事件委托Event delegation是一种事件的响应机制,当需要监听不存在的元素或是动态生成的元素时,可以考虑事件委托。

事件委托得益于事件冒泡(有关事件冒泡可以参考事件冒泡与事件捕获),当监听子元素时,事件冒泡会通过目标元素向上传递到父级,直到document,如果子元素不确定或者动态生成,可以通过监听父元素来取代监听子元素。

举个例子:
假设页面从存在一个ul,其子元素动态生成.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>事件委托</title>
</head>
<body>
  <button>点击</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>

当点击按钮时,ol列表中动态创建li,如果给li添加click事件,当li被点击时,li本身被删除,那么可以这样实现

 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();
      })
 })

但是这样就会使得给每个li都添加了click事件(或者其他的事件),而页面中的li是不确定有多少的,如果页面中生成很多的li,那么就会造成内存占用过多,因此我们可以使用事件委托来解决这个问题。

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

在这个例子中,通过给父级而非子集添加事件,当事件被抛到更上层的父节点的时候,我们通过检查事件的目标对象target来判断并获取事件源li,当子节点被点击的时候,click事件会从子节点开始向上冒泡。父节点捕获到事件之后,通过判断e.target.nodeName来判断是否为我们需要处理的节点。并且通过e.target拿到了被点击的Li节点。从而可以获取到相应的信息,并作处理。

但是当li中有其他的标签时如span标签(或是其他的标签),直接使用上述方法就会导致事件无法被正确触发。

 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()
         }
      }) 
 })

此时,当点击span时,li并未被删除,点击spanli之间的部分li才会被删除,试想当子元素li中有多层嵌套时,就会导致事件无法被正确触发,因此我们需要对li进行判断,判断点击的是否是ol下的li,否则就继续查找,直到查找到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()
      }) 
 })

此时不论li嵌套多少层,liclick事件都会被正确触发。

事件委托可以通过监听父级来达到监听子级的效果,减少了监听器的数量,使用内存也相对减少。当在一些难以追踪的情况下,从DOM从删除的元素仍保留「记忆」(即泄露),这些泄露的「记忆」通常与事件绑定联系在一起,使用事件委托,可以随意的对子元素进行事件绑定而不用担心忘记解绑它们的监听器。

参考:

  1. What is DOM Event delegation?
  2. How JavaScript Event Delegation Works
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 1.背景介绍 1.1什么是事件委托? 事件委托还有一个名字叫事件代理,JavaScript高级程序设计上讲:事件委...
    我叫于搞吧阅读 1,623评论 4 9
  • 一直以来,对js的一些概念还是不清晰的,很多都没有搞明白,今天无意间在群里见他们提起事件委托,所以查找了一些资料,...
    蝴蝶结199007阅读 277评论 1 3
  • 大家好,我是IT修真院成都分院第07期学员,一枚正直善良的web程序员。 一、小课堂简述JS中的事件委托 1.背景...
    120De丶L阅读 320评论 0 0
  • 链接地址:http://www.cnblogs.com/liugang-vip/p/5616484.htmlhtt...
    青春前行阅读 770评论 0 0
  • 下午到新乡了,打扫完卫生铺好床整好衣服收拾完该收拾的,去破街吃了饭,买了没带的东西,太累了...住在外的第一天晚上...
    达浪打啦阅读 120评论 0 0