深入分析javascript中事件委托机制

随着DOM结构的复杂化和Ajax等动态脚本技术的运用,事件委托自然浮出了水面。jQuery为绑定和委托事件提供了.bind()、.live()和.delegate()方法。本文在讨论这几个方法内部实现的基础上,展示它们的优劣势及适用场合。

两个问题

1.元素过多时的性能问题

假设有一个多行多列的表格,我们想让用户单击每个单元格都能看到与其中内容相关的更多信息(比如,通过提示条)。为此,可以为每个单元格都绑定click事件:

$(“info_table td”).bind(“click”, function(){//TODO});
问题是,如果表格中要绑定单击事件的有10列500行,那么查找和遍历5000个单元格会导致脚本执行速度明显变慢,而保存5000个td元素和相应的事件处理程序也会占用大量内存。

2.动态添加元素的无法直接绑定事件

假设一个动态翻页的表格,每一次翻页都是重新插入的表格。通过给第一页添加事件,对后续通过js异步加载的页面没有作用。

基本解决方法

事件委托可以解决上述两个问题。具体到代码上,只要用jQuery1.3新增的.live()方法代替.bind()方法即可:

$(“#info_table td”).live(“click”,function(){//TODO});

这里的.live()方法会把click事件绑定到$(document)对象,而且只需要给$(document)绑定一次,就能够处理后续动态加载表格。在接收到任何事件时,$(document)对象都会检查事件类型和事件目标,如果是click事件且事件目标是td,那么就执行委托给它的处理程序。

基本方法的问题

到目前为止,一切似乎很完美。可惜,事实并非如此。因为.live()方法并不完美,它有如下几个主要缺点:

1. $()函数会找到当前页面中的所有td元素并创建jQuery对象,但在确认事件目标时却不用这个td元素集合,而是使用选择符表达式与event.target或其祖先元素进行比较,因而生成这个jQuery对象会造成不必要的开销;收集td元素并创建jQuery对象,但实际操作的却是$(document)对象,令人费解。

2. 默认把事件绑定到$(document)元素,如果DOM嵌套结构很深,事件冒泡通过大量祖先元素会导致性能损失;

3. 只能放在直接选择的元素后面,不能在连缀的DOM遍历方法后面使用,即$(“#info_table td”).live…可以,但$(“#info_table”).find(“td”).live…不行;

jQuery从1.4开始支持在使用.live()方法时配合使用一个上下文参数:

$(“td”,$(“#info_table”)[0]).live(“click”,function(){//TODO});

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

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

更好的解决办法

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

$(“#info_table”).delegate(“td”,”click”,function(){//TODO});

使用.delegate()有如下优点:

1. 直接将目标元素选择符(”td”)、事件(”click”)及处理程序与“受拖方”$(“#info_table”)绑定,不额外收集元素、事件传播路径缩短、语义明确;

2. 支持在连缀的DOM遍历方法后面调用,即支持$(“table”).find(“#info”).delegate…,支持精确控制;
在jQuery1.7中 .delegate()已被.on()取代,.on与.delegate主要区别在参数顺序。使用.on前面的例子可以这样写:

$(“#info_table”).on(”click”,“td”,function(){//TODO;});
可见,.delegate()与.on()方法是一个相对完美的解决方案。但在DOM结构简单的情况下,也可以使用.live()。

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

例子

<ul id="ul"> 
    <li id="li1">dododo</li> 
    <li id="li2">dododo</li> 
    <li id="li3">dododo</li> 
</ul> 

 如果想对多个li对象进行事件侦听,这时候用事件委托是不二的选择了。事件委托就是利用了事件冒泡,对document中某一个元素进行侦听,其实也就是侦听了其下的所有子元素。

javascript代码如下:

var EventUtil = { 
    addEvent: function(node, type, listener) { 
        if (node.addEventListener) { 
            node.addEventListener(type, listener, false); //firefox 
        } else { 
            node.attachEvent("on"+type, listener); //ie 
        }}, 
    getTarget: function(event){ 
        return event.target || event.srcElement; 
        /**
        在ie下是用event.srcElement,firefox下用event.target
        */ 
    }    

 
var node = document.getElementById("ul"); 
     
EventUtil.addEvent(node,"click",function(event){ 
    alert(EventUtil.getTarget(event).id); 
}); 
 当鼠标单击li元素时,会弹出显示当前li id的警告框,以上代码在ie8, firefox5测试通过

时间: 2024-09-20 17:13:50

深入分析javascript中事件委托机制的相关文章

javascript中事件委托和this面试题

JavaScript不仅门槛低,而且是一门有趣.功能强大和非常重要的语言.各行各业的人发现自己最混乱的选择是JavaSscript编程语言.由于有着各种各样的背景,所以不是每个人都对JavaScript及其基本原理有广泛的认识.通常来书,除非你去参加工作面试才会去思考为什么或者怎么做,否则JavaScript只是你工作的内容. 这个系类的目标是深入探讨JavaScript的一些概念和理论.主题来自于 Darcy Clarke的JavaScript典型面试问题列表.希望你不仅仅是为了答案而阅读完这

如何理解 JavaScript 中的 Promise 机制

本文讲的是如何理解 JavaScript 中的 Promise 机制, Promise 的世界 原生 Promises 是在 ES2015 对 JavaScript 做出最大的改变.它的出现消除了采用 callback 机制的很多潜在问题,并允许我们采用近乎同步的逻辑去写异步代码. 可以说 promises 和 generators ,代表了异步编程的新标准.不论你是否用它,你都得 必须 明白它们究竟是什么. Promise 提供了相当简单的 API ,但也增加了一点学习曲线.如果你以前从没见过

源码-Android中事件传递机制原理

问题描述 Android中事件传递机制原理 我们知道,所有的控件直接或间接的继承子View,View的子类有ViewGroup,并且ViewGroup的子类也会有其他的子View,那么他们之间事件的传递机制是怎样的?对源码有研究的吗? 解决方案 android事件传递机制Android 事件的传递机制Android之事件传递机制 解决方案二: http://blog.csdn.net/pi9nc/article/details/9281829http://www.csdn123.com/html

关于JavaScript中事件绑定的方法总结_javascript技巧

最近收集了一些关于JavaScript绑定事件的方法,汇总了一下,不全面,但是,希望便于以后自己查看. JavaScript中绑定事件的方法主要有三种: 1 在DOM元素中直接绑定 2 JavaScript代码中直接绑定 3 绑定事件监听函数 一.在DOM元素中直接绑定 也就是直接在html标签中通过 onXXX="" 来绑定.举个例子: <input type="button" value="点我呦" onclick="aler

深入分析javascript中的错误处理机制_javascript技巧

前面的话 错误处理对于web应用程序开发至关重要,不能提前预测到可能发生的错误,不能提前采取恢复策略,可能导致较差的用户体验.由于任何javascript错误都可能导致网页无法使用,因此作为开发人员,必须要知道何时可能出错,为什么会出错,以及会出什么错.本文将详细介绍javascript中的错误处理机制 error对象 error对象是包含错误信息的对象,是javascript的原生对象.当代码解析或运行时发生错误,javascript引擎就会自动产生并抛出一个error对象的实例,然后整个程序

我对C#中事件委托的通俗看法

这是我对C#中事件的通俗看法,比较适合初学者(其实我也是初学者)对C#事件的理解,本人因为刚入门,在学习C#的事件原理时,发现很多书上写得很不好理解,不适合初学者,所以我想在这里谈谈我对它的看法,可能不是很准确,如果说得对的,请大家鼓鼓掌,不对的或是不规范的地方,还请高手帮忙更正一下,谢谢了. 在学C#之前,我看过<JAVA编程思想>,还有一些JAVA的入门级的书籍,其中对事件的讲解,总是用事件监听,事件适配器来举例, 所以我就一直认为,在C#中,RUNTIMING会一直监测每个控件的状态,如

深入解读JavaScript中的Hoisting机制_基础知识

hoisting机制 javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面. 先看一段代码 var v = "hello"; (function(){ console.log(v); var v = "world"; })(); 这段代码运行的结果是什么呢? 答案是:undefined 这段代码说明了两个问题, 第一,function作用域里的变量v遮盖了上层作用域变量v.代码做少

Android中事件传递机制的总结

事件传递虽然算不上某个单独的知识点,但是在实际项目开发中肯定会碰到,如果不明白其中的原理,那在设计各种滑动效果时就会感到很困惑. 关于事件的传递,我们可能会有以下疑问: 事件是如何传递的 事件是如何处理的 自定义view的时候,事件也冲突了怎么解决 带着这三个疑问,我们来总结一下事件传递机制是怎么回事.   一.事件分发的原理: 1.事件是如何传递的: (1)首先由Activity分发,分发给根View,也就是DecorView(DecorView为整个Window界面的最顶层View) (2)

JavaScript中的this机制_基础知识

JavaScript有自己的一套this机制,在不同情况下,this的指向也不尽相同. 全局范围 console.log(this); //全局变量 全局范围使用this指向的是全局变量,浏览器环境下就是window. 注:ECMAScript5的strict模式不存在全局变量,这里的this是undefined. 函数调用中 function foo() { console.log(this); } foo(); //全局变量 函数调用中的this也指向全局变量. 注:ECMAScript5的