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 object
function 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 delegation
var 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

转载于:https://www.cnblogs.com/liangzi4000/p/3808487.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值