JS中的事件代理详解

事件代理的定义

对于事件委托或者说事件代理,有这样一段定义:

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

举个例子来说
首先我们创建一个拥有多个平行元素的列表

<ul id="parent-list">  
  <li id="post-1">Item 1</li>   
  <li id="post-2">Item 2</li>   
  <li id="post-3">Item 3</li>   
  <li id="post-4">Item 4</li>   
  <li id="post-5">Item 5</li>   
  <li id="post-6">Item 6</li> 
</ul>  

当鼠标移动到li上或者点击了li的时候,需要触发相应的事件,若果不使用事件代理,那么我们需要为每一个li都添加相应的 onClick()或者 onMouseOver()事件,代码如下:

function addListeners4Li(liNode) {
 liNode.onclick = function clickHandler(){alert('Click')};     
 liNode.onmouseover = function mouseOverHandler(){alert('MouseOver')} 
}

window.onload = function(){
  var ulNode = document.getElementById("parent-list"); 
  var liNodes = ulNode.getElementByTagName("Li"); //获取所有li节点
  for(var i=0, l = liNodes.length; i < l; i++){    
    addListeners4Li(liNodes[i]); //为每一个li节点添加监听
 }

这种方法的缺点在于

  1. 由于在javascript中,每一个函数都是一个对象,是对象就会占用内存,对象越多,占用的内存也就越大,在上面的方法中,我们创建了6个 liNodes对象,对每一个对象进行监听,但是如果li的数量特别庞大时,这种方法其实是很占用内存的
  2. 在上面的方法中,我们对每一个 liNodes对象都添加了监听,而在javascript中,添加到页面中的事件处理程序数量将直接影响程页面的整体性能,因为事件处理程序越多,与dom交互的次数就越多,引起浏览器重绘与重排的次数也就越多,从而拖慢页面的就绪时间。
  3. 如果我们需要频繁的删除和添加 li元素,就需要在每一次添加时都为其绑定事件,过于繁琐。

总结一下就是:

**1. 创建的js对象过多,占用内存

  1. JS与DOM之间的关联过多,影响性能,容易造成内存泄漏
  2. 需要管理的函数过多,对于每个元素都要添加监听**

使用事件代理可以很好的解决这两个问题,但在我们介绍事件代理之前,先要说一下事件的冒泡机制


事件的冒泡及捕获

不同的浏览器对于事件的冒泡及捕获有不同的处理方式,这里主要介绍W3C对DOM2.0定义的标准事件:

图片.png

事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。

事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。

事件冒泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来组织事件的冒泡传播。

其中 addEventListener(eventType,callBack,true | false)函数的第三个属性为 useCapture这个属性默认为 false意为在事件冒泡阶段调用事件处理函数,如果为 true则是在事件捕获阶段调用事件处理函数。


事件代理的使用

对于上面的代码,我们可以使用事件代理来进行简化,只对平行元素共同的父元素进行监听,根据其获取的源事件属性,来做出相应的处理:

document.getElementById("parent-list").addEventListener("click",function(e) { 
  //检查事件源的属性
  if(e.target && e.target.nodeName.toUpperCase == "LI") { 
    console.log("List item ",e.target.id.replace("post-")," was clicked!"); 
  }
}

在上述代码中,在 click()事件的毁掉函数中有一个源事件 e,通过查看源事件中的属性,我们可以确定当前事件是从哪个元素触发的,从而做出相应的Actions

参考:
浅析JavaScript的事件代理和委托
js中的事件委托或是事件代理详解

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,548评论 1 11
  • 1.背景介绍 1.1什么是事件委托? 事件委托还有一个名字叫事件代理,JavaScript高级程序设计上讲:事件委...
    我叫于搞吧阅读 1,676评论 4 9
  • js之事件机制 1、事件初探 1.1 js事件的概述 JavaScript事件:JavaScript是基于事件驱动...
    道无虚阅读 2,420评论 0 2
  • (续jQuery基础(1)) 第5章 DOM节点的复制与替换 (1)DOM拷贝clone() 克隆节点是DOM的常...
    凛0_0阅读 1,371评论 0 8
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,802评论 1 45