深入JS事件冒泡与事件代理(委托)

事件作为DOM操作中重要的一个点,好好的理解并运用相当的重要

1、事件冒泡

简单的说,就是当一个子元素的事件被触发的时候(如onclick事件),该事件会从事件源(被点击的子元素)开始逐级向上传播,触发父级元素的点击事件。

 <div id="parent" style="background-color: #000;height: 400px;width: 400px" data-id="11">  
    <div id="child" style="background-color: #fff;height: 200px;width: 200px" data-id="22"></div>  
 </div> 

document.getElementById('parent').onclick=function () {  
    console.log(this.getAttribute('data-id'));  
};  
document.getElementById('child').onclick=function (e) {  
    console.log(this.getAttribute('data-id'));  
};  

在线运行: http://jsbin.com/ritivosoco/edit?html,js,console,output

这里我们可以发现,当你点击白色区域(子元素),父级的click事件也被触发啦(观察控制台的输出),那么这里就有一个问题啦,可不可以当点击子元素的时候不触发父元素的点击事件啊,这就是接下来要说的啦

2、阻止事件冒泡

所谓阻止事件冒泡其实啊,就是我们不让点击这个事件传递给父元素啊,哈哈,这就要用到事件中的一个stopPropagation()方法啦,还是先看代码吧

document.getElementById('parent').onclick=function () {  
    console.log(this.getAttribute('data-id'));  
};  
document.getElementById('child').onclick=function (e) {  
    console.log(this.getAttribute('data-id'));  
    e.stopPropagation();  
};  

在线运行: http://jsbin.com/ritivosoco/edit?html,js,console,output

嘿嘿,此刻你在线上运行的时候是不是发现当我们点击白色区域的时候并没有触发到父元素的点击事件啊,这是因为我们阻止了子元素的事件冒泡啦!

朋友们有可能会觉得事件冒泡真是烦人,写个事件还要阻止冒泡!不过凡事都有双刃剑,事件冒泡同时给我们带来的还有事件委托这一减少DOM操作的神器,接下来介绍哦

3、事件委托

事件委托,首先按字面的意思就能看你出来,是将事件交由别人来执行,再联想到上面讲的事件冒泡,是不是想到了?对啦,其实就是将子元素的事件通过冒泡的形式交由父元素来执行。

可能在开发的时候会遇到这种情况:如导航每一个栏目都要加一个事件,你可能会通过遍历来给每个栏目添加事件,首先我们来看一段不使用事件委托的代码, 我们遍历子元素数组:

 <ul id="parent">  
   <li>孩子1</li>  
   <li>孩子2</li>  
   <li>孩子3</li>  
   <li>孩子4</li>  
   <li>孩子5</li>
 </ul>
 var ul = document.getElementById('parent')
 var lis = ul.getElementsByTagName('li')
 for (var i = 0; i<lis.length;i++){  
   lis[i].onclick= function() {  
     alert(this.innerHTML);  
   }
 }

这种方式看起来直接明了,但需要多次操作dom(每点击一个li都会操作一次dom),如果子元素较多的话则是一件相当恐怖的事情,而且当我们后面添加一个新的li子元素后,新添加的li没有绑定事件,需要再次给新的li绑定一次,考虑到给新添加的元素绑定事件:

<ul id="parent">  
   <li>孩子1</li>  
   <li>孩子2</li>  
   <li>孩子3</li>  
   <li>孩子4</li>  
   <li>孩子5</li>
 </ul>
 var ul = document.getElementById('parent')
 var lis = ul.getElementsByTagName('li')
 function addClick() {
   for (var i = 0; i<lis.length;i++){  
     lis[i].onclick= function() {  
       alert(this.innerHTML);  
     }
   }
}
addClick()

function addElement() {  
   var li = document.createElement('li');  
   li.innerHTML="我是新孩子";  
   ul.appendChild(li);  
   addClick();  
} 
addElement();  

上面写的代码确实可以解决新添加子元素的问题,但代码就有点多了,而且本质上并没有改变DOM的操作次数,优化性能,下面我们直接来看事件委托的写法:

<ul id="parent">
  <li>孩子1</li>  
  <li>孩子2</li>  
  <li>孩子3</li>  
  <li>孩子4</li>  
  <li>孩子5</li>
</ul>

var ul = document.getElementById('parent');  
ul.onclick = function (e) {  
  //判断只有li触发的才会输出内容  
  if(e.target.nodeName.toLowerCase() === "li"){
    alert(e.target.innerHTML);  
  }  
  e.stopPropagation();                          
}

在线运行: http://jsbin.com/bamonabeda/16/edit?html,js,console,output

因为是监听的父元素,所有即使新添加元素也是可以默认绑定好事件的,这样我们可以看到代码更简洁了,也减少了dom的操作次数,是不是非常的优雅和nice啊!

4、总结

最后总结下哈,事件冒泡是个双刃剑,当对我们有负面的影响的时候就显得相当讨厌,不过我们可以用阻止冒泡来达到我们想要的效果;但是在另一方面在特定的场合我们又可以借助于事件冒泡来优化我们的代码,优化性能,只有对原理了解于心,才可以突破更多的限制

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

推荐阅读更多精彩内容