事件委托技术原理和使用(js,jquery)

件委托技术原理和使用(js,jquery)

原创  2016年03月10日 11:18:56

一:事件委托技术原理 摘自http://www.webhek.com/event-delegate/

事件委托(event delegation),使用时间委托技术能让你避免对特定的每个节点添加事件监听器;相反,事件监听器是被添加到它们的父元素上。事件监听器会分析从子元素冒泡上来的事件,找到哪个是子元素的事件。

   首先,我们设定一个列表

<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元素可能会被删除,可能会有新增,监听它们的新增或删除事件将会是一场噩梦,尤其是当你的监听事件的代码放在应用的另一个地方时。但是,如果你将监听器安放到它们的父元素上呢?你如何能知道是那个子元素被点击了?

简单:当子元素的事件冒泡到父ul元素时,你可以检查事件对象的target属性,捕获真正被点击的节点元素的引用。下面是一段很简单的JavaScript代码,演示了事件委托的过程:

[html]  view plain  copy
  1. //找到父元素,添加监听器。。。  
  2. document.getElementById('parent-list').addEventListener('click', function (e) {  
  3.     //e.target是被点击的元素  
  4.     //如果被点击的是li元素  
  5.     if(e.target && e.target.nodeName == 'Li') {  
  6.         //执行操作,,,  
  7.         console.log('List item', e.target.id.replace('post-'), "was clicked")  
  8.     }  
  9. })  

第一步是给父元素添加事件监听器。当有事件触发监听器时,检查事件的来源,排除非 li子元素事件。如果是一个 li元素,我们就找到了目标!如果不是一个 li元素,事件将被忽略。这个例子非常简单, ULli是标准的父子搭配。让我们试验一些差异比较大的元素搭配。假设我们有一个父元素 div,里面有很多子元素,但我们关心的是里面的一个带有”classA” CSS类的A标记:

[javascript]  view plain  copy
  1. //获取父元素DIV,添加监听器  
  2. document.getElementById('myDiv').addEventListener('click', function (e) {  
  3.     //e.target是被点击的节点  
  4.     if (e.target && e.target.nodeName == 'A') {  
  5.         //获取css类名  
  6.         var classes = e.target.className.split(' ');  
  7.         if (classes) {  
  8.             for (var x = 0; x< class.length; x++) {  
  9.                 if (class[x] == 'classA') {  
  10.                     //找到元素 可以操作了  
  11.                     console.log('Anchor element clicked');  
  12.                 }  
  13.             }  
  14.         }  
  15.     }  
  16. })  

上面这个例子中不仅比较了标签名,而且比较了CSS类名。虽然稍微复杂了一点,但还是很具代表性的。比如,如果某个A标记里有一个 span标记,则这个 span将会成为target元素。这个时候,我们需要上溯DOM树结构,找到里面是否有一个 A.classA 的元素。

  


二:jquery中事件委托优化http://www.jb51.net/article/28770.htm

jQuery为绑定和委托事件提供了.bind()、.live()和.delegate()方法。本文在讨论这几个方法内部实现的基础上,展示它们的优劣势及适用场合。

事件委托就是事件目标自身不处理事件,而是把处理任务委托给其父元素或者祖先元素,甚至根元素(document)。


.bind

$("info_table td").bind("click", function(){/*显示更多信息*/});

bind()只能给调用它的时候已经存在的元素绑定事件,不能给未来新增的元素绑定事件(类似于新来的员工收不到快递)


.live

$("#info_table td").live("click",function(){/*显示更多信息*/}); 解决了.bind的问题,将事件绑定到document对象,能够处理后续添加元素的单击事件


缺点:

$()函数会找到当前页面中的所有td元素并创建jQuery对象,但在确认事件目标时却不用这个td元素集合,而是使用选择符表达式与event.target或其祖先元素进行比较,因而生成这个jQuery对象会造成不必要的开销;
默认把事件绑定到$(document)元素,如果DOM嵌套结构很深,事件冒泡通过大量祖先元素会导致性能损失; 
只能放在直接选择的元素后面,不能在连缀的DOM遍历方法后面使用,即$("#infotable td").live...可以,但$("#infotable").find("td").live...不行;
收集td元素并创建jQuery对象,但实际操作的却是$(document)对象,令人费解。

解决方法:

为了避免生成不必要的jQuery对象,可以使用一种叫做“早委托”的hack,即在$(document).ready()方法外部调用.live(): 

[html]  view plain  copy
  1. (function($){  
  2. $("#info_table td").live("click",function(){/*显示更多信息*/});  
  3. })(jQuery);   

在此,(function($){...})(jQuery)是一个“立即执行的匿名函数”,构成了一个闭包,可以防止命名冲突。在匿名函数内部,$参数引用jQuery对象。这个匿名函数不会等到DOM就绪就会执行。注意,使用这个hack时,脚本必须是在页面的head元素中链接和(或)执行的。之所以选择这个时机,因为这时候刚好document元素可用,而整个DOM还远未生成;如果把脚本放在结束的body标签前面,就没有意义了,因为那时候DOM已经完全可用了。

为了避免事件冒泡造成的性能损失,jQuery从1.4开始支持在使用.live()方法时配合使用一个上下文参数: 

$("td",$("#info_table")[0]).live("click",function(){/*显示更多信息*/});这样,“受托方”就从默认的$(document)变成了$("#infotable")[0],节省了冒泡的旅程。不过,与.live()共同使用的上下文参数必须是一个单独的DOM元素,所以这里指定上下文对象时使用的是$("#infotable")[0],即使用数组的索引操作符来取得的一个DOM元素。

.delegate()

如前所述,为了突破单一.bind()方法的局限性,实现事件委托,jQuery 1.3引入了.live()方法。后来,为解决“事件传播链”过长的问题,jQuery 1.4又支持为.live()方法指定上下文对象。而为了解决无谓生成元素集合的问题,jQuery 1.4.2干脆直接引入了一个新方法.delegate()。

使用.delegate(),前面的例子可以这样写: 

$("#info_table").delegate("td","click",function(){/*显示更多信息*/}); 
使用.delegate()有如下优点(或者说解决了.live()方法的如下问题): 

直接将目标元素选择符("td")、事件("click")及处理程序与“受拖方”$("#info_table")绑定,不额外收集元素、事件传播路径缩短、语义明确; 
支持在连缀的DOM遍历方法后面调用,即支持$("table").find("#info").delegate...,支持精确控制; 
可见,.delegate()方法是一个相对完美的解决方案。但在DOM结构简单的情况下,也可以使用.live()。 

提示:使用事件委托时,如果注册到目标元素上的其他事件处理程序使用.stopPropagation()阻止了事件传播,那么事件委托就会失效。 

结论 
在下列情况下,应该使用.live()或.delegate(),而不能使用.bind(): 

为DOM中的很多元素绑定相同事件; 
为DOM中尚不存在的元素绑定事件; 

PS:根据jQuery 1.7 Beta 1的发版说明,jQuery 1.7为了解决.bind()、.live()和.delegate()并存造成的不一致性问题,将会增加一对新的事件方法:.on()和.off():
$(elems).on(events, selector, data, fn);
$(elems).off(events, selector, fn);
如果指定selector,则为事件委托;否则,就是常规绑定。新旧API对应如下: 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值