事件代理的定义
对于事件委托或者说事件代理,有这样一段定义:
事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
举个例子来说
首先我们创建一个拥有多个平行元素的列表
<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节点添加监听
}
这种方法的缺点在于
- 由于在javascript中,每一个函数都是一个对象,是对象就会占用内存,对象越多,占用的内存也就越大,在上面的方法中,我们创建了6个
liNodes
对象,对每一个对象进行监听,但是如果li的数量特别庞大时,这种方法其实是很占用内存的 - 在上面的方法中,我们对每一个
liNodes
对象都添加了监听,而在javascript中,添加到页面中的事件处理程序数量将直接影响程页面的整体性能,因为事件处理程序越多,与dom交互的次数就越多,引起浏览器重绘与重排的次数也就越多,从而拖慢页面的就绪时间。 - 如果我们需要频繁的删除和添加
li
元素,就需要在每一次添加时都为其绑定事件,过于繁琐。
总结一下就是:
**1. 创建的js对象过多,占用内存
- JS与DOM之间的关联过多,影响性能,容易造成内存泄漏
- 需要管理的函数过多,对于每个元素都要添加监听**
使用事件代理可以很好的解决这两个问题,但在我们介绍事件代理之前,先要说一下事件的冒泡机制
事件的冒泡及捕获
不同的浏览器对于事件的冒泡及捕获有不同的处理方式,这里主要介绍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
网友评论