经过javascript 事件委托 探讨live() bind()

传统的事件处理javascript

    事件委托就是在一个页面上使用一个事件来管理多种类型的事件。这并非一个新的想法,但对于把握性能来讲却很重要。一般状况,你会在web应用程序中看到这样的代码:html

document.getElementById("help-btn").onclick = function(event){ openHelp(); }; 
document.getElementById("save-btn").onclick = function(event){ saveDocument(); }; 
document.getElementById("undo-btn").onclick = function(event){ undoChanges(); };java



    这种传统的编码方式给每一个元素分配单独的事件处理方法。对于交互少的站点来讲,这样作是能够的。然而,对于大型的wen应用程序,当存在大量的事件处理的时候,就会显得反应迟钝。这里要关注的不是速度问题,而是内存占用问题。若是有数百个交互,DOM元素和JavaScript代码就会有数百个关联。web应用须要占用的内存越多,它的响应速度就越慢。事件委托能将这个问题减少。
web


事件冒泡及捕获浏览器

    要不是事件的下面这些属性,事件委托将成为可能。早期的web开发,浏览器厂商很难回答一个哲学上的问题:当你在页面上的一个区域点击时,你真正感兴趣的是哪一个元素。这个问题带来了交互的定义。在一个元素的界限内点击,显得有点含糊。毕竟,在一个元素上的点击同时也发生在另外一个元素的界限内。例如单击一个按钮。你实际上点击了按钮区域、body元素的区域以及html元素的区域。函数

伴随着这个问题,两种主流的浏览器Netscape和IE有不一样的解决方案。Netscape定义了一种叫作事件捕获的处理方法,事件首先发生在DOM树的最高层对象(document)而后往最深层的元素传播。在图例中,事件捕获首先发生在document上,而后是html元素,body元素,最后是button元素。性能

IE的处理方法正好相反。他们定义了一种叫事件冒泡的方法。事件冒泡认为事件促发的最深层元素首先接收事件。而后是它的父元素,依次向上,知道document对象最终接收到事件。尽管相对于html元素来讲,document没有独立的视觉表现,他仍然是html元素的父元素而且事件能冒泡到document元素。因此图例中噢噢那个button元素先接收事件,而后是body、html最后是document。编码



    在定义DOM的时候,W3C显然看到了这两种方案各自的优势,因此DOM Level 2的事件规范中同时定义了这两种方案。首先document元素得到事件,而后捕获阶段向与事件最相关的元素传播,当事件被此元素捕获后,再冒泡到document元素。addEventListener()方法接受三个参数:事件名,事件处理函数,一个用于指定事件在捕获阶段处理仍是在冒泡阶段处理的布尔值。大部分的web开发者都会使用false做为第三个参数这样就跟IE中的attachEvent()同样了。spa

//bubbling phase handler 
document.addEventListener("click", handleClick, false);
//capturing phase handler 
document.addEventListener("click", handleClick, true);orm



经过冒泡实现事件委托

事件委托的关键就是在经过冒泡方式实如今最高层(一般是document)处理事件。不是全部的事件都支持冒泡,可是鼠标和键盘事件支持,而且这也是你所关心的。回顾下前面的例子,你能够经过在document上分配一个事件来处理全部的单击事件,只须要经过区别节点来决定处理事件的方法。


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?
        }
};


使用事件委托,数个事件处理函数可使用一个函数来管理。全部的单击事件被委托给一个合适的函数来处理。一样,mousedownmouseupmousemovemouseovermouseoutdblclickkeyupkeydown,  和keypress事件也能够这样处理。可是,在事件委托中mouseover和mouseout的处理方法是不一样的,当鼠标从一个元素移动到它的子元素内的时候,被认为是"out"。


注意:你也可使用事件捕获来完成事件委托,但这只能用在支持事件捕获的非IE浏览器中。


优势

事件委托对于web应用程序的性能有以下几个优势:

1.须要管理的函数变少了

2.占用的内存少了

3.javascript代码和Dom结构之间的关联更少了

4.在改变DOM结构中的innerHTML时,不须要改动事件处理函数


从传统的事件处理方法转向事件委托提升了大型web应用的性能。正由于它如此的重要,一些相似于YUI、jQuey的javascript库也开始将事件委托应用在它们的核心接口中。实现事件委托是很轻松的,却能带来性能上很大的提升。尤为表如今你将数十个事件处理函数整合到一个函数里。试一下事件委托,你就不会再使用传统的事件处理方法了。



bind() 是直接绑定在元素上,而 live() 是经过冒泡的方式来绑定到元素上。举两个应用场景来讲明他们的存在:

第1、有一个按钮,你想要用他来在点击的时候经过 AJAX 提交 form 的请求。

由于这里只有一个按钮,只绑定一次,你并不须要冒泡这种更费力费资源的方式来冒泡到 document 再指定这个元素。

第2、在一个有 20个以上,甚至更多个 li 的 ul 列表中,要让每个 li 点击的时候都去触发相应函数的时候。

若是给每一个 li 都绑定一个 click 事件,这样是否是很蛋疼?这时经过 live()(固然更好是用 delegate() 这样的方法,能够指定一个离 li 更近的父节点),其实只在 document 上绑定一次 click() 事件,你省了 19 次绑定。这是多省内存的事。对吧?

相关文章
相关标签/搜索