Javascript的事件委托
原文: http://www.nczonline.net/blog/2009/06/30/event-delegation-in-javascript/#
?
传统的事件处理所谓事件委托即使用单个Event Handler来管理页面上特定的一类事件。这并不是什么新的idea,但对于Web应用的性能而言,是很重要的。比如,有时候,你可能会写如下的代码:
????? 在这个问题被提出来的时候,当时的两个主要浏览器(Netscape Navigator 和 Internet Explorer)采取了不同方式来解决这个问题。Netscape使用了一种叫做事件捕捉的机制,事件首先发生在DOM树上最高层的元素上,然后逐层往下传递到最深的被影响的元素上。所以,在上述例子中,点击事件首先由document元素来处理,然后是html元素,接下来是body,最后才是button元素。
????? Internet Explorer正好使用了完全相反的方式。他们称之为事件冒泡:最底层的元素应该首先接受到这个时间,然后才是它的父节点,祖父节点……一直到最高层的document元素。值得注意的是,虽然document和<html>元素对应的是页面上同一个可视元素,但它们在DOM树上却是父子关系。Event Bubbling的终点是document元素。
在定义DOM的时候,W3C显然注意到了两种不同方式各自的好处,因此我们现在使用的DOM Level 2事件机制中同时包含了这两种方式。一开始document元素接收到这个事件,进入捕获阶段,将其传递到最底层的元素。在这个元素的处理逻辑完成以后,进入冒泡阶段,将其传递回到document。在DOM Level2事件API中,addEventListener方法接受三个参数:要处理的事件名,事件处理函数,一个bool值(true表示在捕获阶段处理事件,而false表示在冒泡阶段处理事件)。多数Web开发人员经常会被告知使用false作为参数值,以保持和IE中的attachEvent方法相同的行为。比如:
document.onclick = function(event){ //IE doesn't pass in the event object event = event || window.event; //IE uses srcElement as the target var target = event.target || event.srcElement; switch(target.id){ case "help-btn": openHelp(); break; case "save-btn": saveDocument(); break; case "undo-btn": undoChanges(); break; //others? }};事件委托可以让同一事件的处理入口都汇集到一个函数中。所有的click事件现在都会先被单个函数所处理,并根据时间的对象元素委托给合适的函数。同样的,我们把它应用于
mousedown,mouseup,mousemove,mouseover,mouseout,dblclick,keyup,keydown, 和keypress事件. 这里要注意的一点就是,由于mouseover和mouseout事件的特性(仅当鼠标移出容器时才会触发mouseout),事件代理对它们来说并不是很实用。当然,你也可以通过事件捕获来完成Event delegation,但这仅在支持事件捕获的浏览器中有效,也就是说IE不支持该方式。
好处对于一个web应用来说,事件代理具有以下几点好处:
较少的事件处理函数.占用更少的内存.减少了Javascript和DOM之间的耦合.
在改变元素的innerHTML时,不用去移除绑定事件处理函数.相比于传统的事件处理方式,事件委托提高了大型web应用的总体性能。它对于Javascript库至关重要,如YUI和jQuery已经使用了这种机制。实现事件委托并不难,但是在用户界面的性能上的提高确实非常显著的。这在你将大量的事件处理函数合并为一个的时候,尤其明显。试试事件委托机制吧!
?