首页 > 网站 > WEB开发 > 正文

Javascript的事件委托和事件处理

2024-04-27 14:22:16
字体:
来源:转载
供稿:网友

javascript的事件委托和事件处理

随着Ajax和RIA越来越成为主流,Javascript对事件(Event)的支持也得到了越来越多的关注。像雅虎这样的公司正在突破RIA的极限,让web应用程序在浏览器中更有效的运行,就像桌面应用程序一样。雅虎的邮箱应用就是一个很好的例子。

雅虎的一些工程师给我们展示了提高Javascript应用程序性能的技术。其中有提到强大的事件处理架构。提高性能的要旨就是用事件委托(Event Delegation)而非传统的事件处理(Event Handling)。

我发现一个问题是,网上大部分的例子是用YUI编写的,隐藏了背后的Javascript。在这边文章中,我会给出纯Javascript版本的事件代理的例子。

传统的Javascript事件处理和Unobtrusive Javascript

传统的Javascript时间处理并不是有效率的。一个强大的Ajax和RIA应用程序,它会有大量的用户交互接口。所有的这些用户交互接口会有一个对应的事件处理,所有的这些事件处理需要捆绑在一起才可以被用户触发。

如果用现今的技术,Unobtrusive scripting,这是一个将事件和脚本从(X)HTML中剥离的技术。它将访问DOM并通过content,PResentation, behivor分离的技术来附加脚本到对象中。(X)HTML中再也不会出现onclick这样的时间处理代码。

在传统的Javascript中,把所有的事件捆绑在一起是有代价的。不仅是捆绑它们的步骤很多,而且重复的代码占用浏览器内存。不仅仅如此,如果你改变DOM,新添加的元素不会注意到onload事件,你需要重新设置事件。

请看下面的代码:

<ul id="listing">    <li><a href="#">Handlers Test</a></li>    <li><a href="#">Handlers Test</a></li>    <li><a href="#">Handlers Test</a></li>    <li><a href="#">Handlers Test</a></li></ul>
window.onload = function(){   var x = document.getElementById("listing");       x = x.getElementsByTagName("a");   for (var i = 0; i < x.length; i++){     (function(){        var z = i;        x[i].onclick = function(){           alert("clicking" + z);           return false;        };      })();   }}

这段代码会查找里列表中所有的锚点,并给它们分别添加一个匿名函数。这很好的做到了unobtrusive。但是我们却在点击事件上消耗了大量的浏览器内存。你能想象如果一个更大的列表是什么样子吗?

合并所有的用户交互接口,你就会有类似下面的一个场景:

对象+事件,对象+事件,对象+事件... = 一个捆绑在一起的集合

事件委托(Event Delegation)和事件冒泡(Event Bubbling)

基本原理是将事件绑定在文档对象中更小的一个集合上,而不是绑定到每个元素上。因为Javascript的事件冒泡机制(Event Bubbling)暴露this,所以可以检测到this指向的当前元素。事件冒泡的主张是,每一个被点击的元素,会注册一个点击事件,该事件会沿着DOM的树向上冒泡直到DOM的根结点。你可以捕捉这个事件,并检测页面中最初的事件源和当前元素。

雅虎的很多工程师用YUI展示了事件委托的例子,这里我将用Javascript重新演示这个例子。本例子给出了两个可以折叠的无序列表。第一个列表用传统的事件处理来实现,第二个用事件委托来实现。这两个例子都可以正常的工作,一旦你修改DOM,则只有第二个例子能工作了。

首先你需要一个函数来获取事件对象(Event Target)(W3C事件模型中的定义),或者事件源(Event Source)(IE浏览器中的定义),下面就是这个神奇的函数:

// get and identify the source of the event objectfunction getTarget(x){    x = x || window.event;    return x.target || x.srcElement;}

你可以通过下面的代码来获取事件的目标节点

two.onclick = function(e){  // delegate, pass in the event object ! !  var t = getTarget(e);  // take conditional action ! !  if (t.nodeName.toLowerCase() === 'a') {..... 

接下来你就可以在onclick事件上写需要的代码了。完整的例子请看这里,Javascript代码如下:

// event delegationvar setup = function(){    // just get our stuff    var one = document.getElementById("collapse_one");    var two = document.getElementById("collapse_two");        one.className = "dynamic";        two.className = "dynamic";        // start traditional event handlers    function toggle(el) {        var ul = el.parentNode.getElementsByTagName('ul')[0];        if (ul.style.display == 'none' || ul.style.display == ''){            ul.style.display = 'block';        } else {            ul.style.display = 'none';        }        return false;    };    var uls = one.getElementsByTagName("ul");    for (var i=0; i<uls.length; i++){        var parentLink = uls[i].parentNode.getElementsByTagName('a')[0];            parentLink.onclick = function(){                return toggle(this);            };    };    // end traditional event handlers        // start event delegation    var uls = two.getElementsByTagName("ul");    two.onclick = function(e){        var t = getTarget(e); // delegate!!        if (t.nodeName.toLowerCase() === 'a' && t.parentNode.getElementsByTagName('ul').length > 0) {            var ul = t.parentNode.getElementsByTagName('ul')[0];            if (ul.style.display == 'none' || ul.style.display == ''){                ul.style.display = 'block';            } else {                ul.style.display = 'none';            }            return false;        };    };        function getTarget(x){ // here's the magic, really simple stuff        x = x || window.event;        return x.target || x.srcElement;    }    // end event delegation        // general utilities    function addElements(){            var extraHTML = ['<li><a href="#">New Item</a><ul>' ,                '<li><a href="#">Sub Item 1</a><li><a href="#">Sub Item 2</a>' ,                '<li><a href="#">Sub Item 3</a><li><a href="#">Sub Item 4</a>' ,                '<li><a href="#">Sub Item 5</a><li><a href="#">Sub Item 6</a>' ,                '</li></ul></li>'].join('');                one.innerHTML += extraHTML;                two.innerHTML += extraHTML;        }    // using, gasp! event handler    document.getElementById("myButton").onclick = addElements;};window.onload = setup;
View Code

本例中,我们将事件绑定在指定元素的上层节点,其实也可以直接将事件绑定在docuemnt节点上。

关于事件委托的结论

  • 更容易绑定
  • 可以将所有的事件处代码理集中放在一个地方(就像一个交警),可以分流不同的事件。
  • 在DOM加载完之后修改DOM,也不会影响事件的正常工作
  • 使用更少的浏览器内存,所以会有更高的性能,特别是在大型的web应用中

原文地址:http://v1.cherny.com/webdev/70/javascript-event-delegation-and-event-hanlders


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表