jQuery的delegate
jQuery的delegate
在网页开发的过程中经常遇到的一个需求就是点击一div内部做某些操作,而点击页面其它地方隐藏该div。比如很多导航菜单,当菜单展开的时候,就会要求点击页面其它非菜单地方,隐藏该菜单。
先从最简单的开始,假如页面有一个id为test的div,我们要实现点击页面其它地方隐藏该div:
<div id="test" style="margin:100px;background-color:#3e3;width:100px;height:100px;"> </div>
对于这个问题一般有两种思路,这两种思路都会利用事件冒泡这一原理,想要详细了解Javascript事件机制可以看看JavaScript与HTML交互——事件,这不是本文重点,所以这里只是简单介绍一下事件冒泡,
事件冒泡
IE的事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的元素
Netscape的事件捕获:不太具体的节点更早接收事件,而最具体的元素最后接收事件,和事件冒泡相反
DOM事件流:DOM2级事件规定事件流包括三个阶段,事件捕获阶段,处于目标阶段,事件冒泡阶段,首先发生的是事件捕获,为截取事件提供机会,然后是实际目标接收事件,最后是冒泡句阶段。
Opera、Firefox、Chrome、Safari都支持DOM事件流,IE不支持事件流,只支持事件冒泡
如有以下html,点击div区域,按照不同的模型事件元素的click事件触发顺序如下所示:

<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Test Page</title>
</head>
<body>
<div>
Click Here</div>
</body>
</html>

在触发DOM上的某个事件的时候会产生一个事件对象event,这个对象包含着所有与事件有关的信息,包括产生事件的元素、事件类型等相关信息。所有浏览都支持event对象,但支持方式不同。事件对象有一个方法(W3C:stopPropagation)/属性(IE:cancelBulle=true)可以阻止事件继续冒泡或捕获。我们如果想在事件冒泡到某元素时阻止冒泡可以写一个这样的兼容浏览器方法:

function stopPropagation(e) {//把事件对象传入
if (e.stopPropagation) //支持W3C标准
e.stopPropagation();
else //IE8及以下浏览器
e.cancelBubble = true;
}

因为所有的浏览器都支持事件冒泡,浏览器兼容性考虑,我们一般绑定事件的的时候都会利用事件冒泡而不是事件捕获。了解了这个之后我们可以看看下面两种思路了。
思路一
第一种思路分两步
第一步:对document的click事件绑定事件处理程序,使其隐藏该div
第二步:对div的click事件绑定事件处理程序,阻止事件冒泡,防止其冒泡到document,而调用document的onclick方法隐藏了该div。

<script type="text/javascript">
function stopPropagation(e) {
if (e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
} $(document).bind('click',function(){
$('#test').css('display','none');
}); $('#test').bind('click',function(e){
stopPropagation(e);
});
</script>

这样当点击页面非div区域的时候,直接或层层冒泡会调用document的onclick方法,隐藏该div,而点击div或其子元素的时候,事件总会冒泡的div本身,这时候会阻止事件继续冒泡,不会调用doument的onclick方法致使div被隐藏,从而完成了我们的需求。
思路二
我们之前提到,在触发DOM上的某个事件的时候会产生一个事件对象event,这个对象包含着所有与事件有关的信息,包括产生事件的元素、事件类型等相关信息,思路一中div的click事件处理程序传入的参数就是这个event对象。访问IE中的event对象有几种不同的方式,取决于指定事件处理程序的方法。直接为DOM元素添加事件处理程序时,event对象作为window对象的一个属性存在。
event对象包含了一个重要属性:target(W3C)/srcElement(IE),这个属性标识了触发事件的原始元素,思路二就是要利用这个属性。我们可以直接对document的click事件绑定事件处理程序,在事件处理程序中判读事件源是否为id==test的div元素或其子元素,如果是则方法return不做操作,如果不是则隐藏该div。

<script type="text/javascript">
$(document).bind('click',function(e){
var e = e || window.event; //浏览器兼容性
var elem = e.target || e.srcElement;
while (elem) { //循环判断至跟节点,防止点击的是div子元素
if (elem.id && elem.id=='test') {
return;
}
elem = elem.parentNode;
} $('#test').css('display','none'); //点击的不是div或其子元素
});
</script>

这样当点击页面任何地方的时候都会层层冒泡至document的click事件,事件处理程序会判断事件源是否为id==test的div或其子元素,如果是方法return,否则隐藏该div,也能够实现我们的需求。
注意点及优劣
这两种思路都依赖于事件冒泡,所以我们在处理其它相关元素的click事件的时候一定要注意这点,避免其他相关元素的click事件处理程序中包含阻止事件冒泡代码而影响了该功能。
这两种方式都很容易理解,貌似思路一更优秀一些,看起来它的处理更简单一些,不用去层层判断事件源,直接把click事件绑定在该div上。在这个例子中确实如此,但是有些复杂的页面就不尽然了,假如我们有一个页面,上面有数十个div都需要点击页面其它地方隐藏这类问题

<div class="dialogs">
<div class="dialog">
<div id="1">1</div>
<div id="2">2</div>
</div>
<div class="dialog">
<div id="1">1</div>
<div id="2">2</div>
</div>
<div class="dialog">
<div id="1">1</div>
<div id="2">2</div>
</div>
...
</div>

我们用思路一写出的代码可能是这样:

<script type="text/javascript">
function stopPropagation(e) {
if (e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
} $(document).bind('click',function(){
$('.dialog').css('display','none');
}); $('.dialog').bind('click',function(e){
stopPropagation(e);
}); </script>

看起来简单依旧的样子,但是我们仔细想想就会发现问题,我们在每个dialog上都绑定了类似的方法,维护如此多的click事件处理程序对内存来说绝对是可开销,导致我们页面运行缓慢。而且如果我们可以动态使用ajax创建新dialog问题又来了,新创建的dialog不能实现隐藏功能!因为绑定函数已经执行完了,不会再为新的dialog绑定click事件处理程序,我们只能自己来做此事。也就是说思路一无法把处理程序附加到可能还未存在于DOM中的DOM元素之上。因为它是直接把处理程序绑定到各个元素上,它不能把处理程序绑定到还未存在于页面中的元素之上。
这时候就是思路二展示身手的时候了,我们看看思路二在这种时候代码的书写

<script type="text/javascript">
$(document).bind('click',function(e){
var e = e || window.event;
var elem = e.target || e.srcElement;
while (elem) {
if (elem.className && elem.className.indexOf('dialog')>-1) {
return;
}
elem = elem.parentNode;
} $('#test').css('display','none');
});
</script>

改动也相当的小,我们来看看是不是能解决上边的两个问题了,首先无论多少个dialog我们只是绑定了一个click事件处理程序,对性能影响不大,添加一个新的dialog思路二的代码还好不好使呢,依旧好使,这样我们就能发现在复杂页面的情况下实际上思路二是一种更优秀的解决方案。
这些都明白了,我们就能说说本文的第二个主角jQuery的delegate方法了。
delegate
首先看看jQuery官方对delegate的语法及描述
.delegate( selector, eventType, handler(eventObject) )
Description: Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements.
delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数。
使用 delegate() 方法的事件处理程序适用于当前或未来的元素(比如由脚本创建的新元素)。
$( "table" ).delegate( "td", "click", function() {
$( this ).toggleClass( "chosen" );
});
通过上面语句我们就可以为所有table的td绑定click事件处理程序。
delegate方法设计意图在于把处理程序附加到单个元素上或是一小组元素之上,监听后代元素上的事件而不是循环遍历并把同一个函数逐个附加到DOM中的多个个元素上。把处理程序附加到一个(或是一小组)祖先元素上而不是直接把处理程序附加到页面中的所有元素上,从而带来性能上的优化。
jQuery版隐藏dialog
通过上面知识我们可以发现jQuery的delegate方法可以方便实现我们隐藏div的需求

<script type="text/javascript">
$('.dialogs').delegate('.dialog','click',function(){
$(this).css('display','none');
});
</script>

使用jQuery我们发现比我们思路二在性能上又有了小幅提升,因为我们不需要冒泡至document处理了,只需要在dialog的父元素就可以处理完成了,可以不至于把很多类似功能都绑定到document上,需要注意的一点就是jQuery已经贴心的帮我们把this处理为事件源,处理起来更是如鱼得水了。
delegate与bind
通过上面我们说一堆我们可以在权衡使用bind还是delegate上有一定依据了,如果就单独绑定一个元素的事件处理程序,用bind还是很合适的,但是如果处理很多类似元素的事件处理程序的时候不妨考虑一下delegate,看看是否对提高性能有所帮助。
jQuery的delegate的更多相关文章
- 关于Jquery的delegate绑定事件无效
今天在做一个页面,用的是easyui页面有很多的tabs,里面都放了iframe 需要在load事件动态调整iframe高度 发现始终无法使用delegate来绑定load事件. 纠结了一下午发现了问 ...
- 点击页面其它地方隐藏div所想到的jQuery的delegate
在网页开发的过程中经常遇到的一个需求就是点击一div内部做某些操作,而点击页面其它地方隐藏该div.比如很多导航菜单,当菜单展开的时候,就会要求点击页面其它非菜单地方,隐藏该菜单. 先从最简单的开始, ...
- jQuery的delegate()与proxy()方法
1. jQuery 事件 - delegate() 方法 定义和用法 delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数. 使用 ...
- 由点击页面其它地方隐藏div所想到的jQuery的delegate
对于这个问题一般有两种思路,这两种思路都会利用事件冒泡这一原理,想要详细了解Javascript事件机制可以看看JavaScript与HTML交互——事件,这不是本文重点,所以这里只是简单介绍一下事件 ...
- jQuery的 delegate问题
习惯了bind,用惯了live,就不习惯delegate了呀有木有... 支持为动态生成的标签元素绑定事件也许就live和delegate了吧,不过新版本已经不支持live了,只有delegate d ...
- jQuery中delegate与on的用法与区别
在jQuery1.7中 .delegate()已被.on()取代.对于早期版本,它仍然使用事件委托的最有效手段. 在事件绑定和委派,delegate()和on在一般情况下,这两种方法是等效的. .de ...
- jQuery 事件 - delegate() 方法
<html><head><script type="text/javascript" src="/jquery/jquery.js" ...
- jquery .live() .delegate() .bind() .click()区别
什么是.live()? 除了让你对Dom元素现在和将来绑定事件之外,.live() 方法和.bind()方法很像.你可以用.live()方法对没有存在的Dom节点绑定事件.考虑下面的情况. 当用户要离 ...
- javascript 原生实现 jquery live/delegate
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...
随机推荐
- C#随机双色球
using System; using System.Collections.Generic; namespace ConsoleApplicationRandnumber { class Progr ...
- AngularJS应用开发思维之3:依赖注入
找不到的API? AngularJS提供了一些功能的封装,但是当你试图通过全局对象angular去 访问这些功能时,却发现与以往遇到的库大不相同. $http 比如,在jQuery中,我们知道它的AP ...
- jenkins综合cobertura,来电显示cobertura的report
我的项目是使用maven作为构建工具.左右maven如何整合jenkins请参阅: http://blog.csdn.net/yaominhua/article/details/40684355 本文 ...
- CentOs Linux 常见命令
整理一些常用的命令(持续更新): 查看端口是否开启: netstat -an | grep prot (查看是否打开23端口) |:通道的意思,grep是指查看当前字符所在的行 LINUX通过下面的命 ...
- springMVC 获取本地项目路径 及后整理上传文件的方法
String path=request.getSession().getServletContext().getRealPath("upload/img/product"); // ...
- 关于phpcms中模块_tag.class.php中的pc_tag()方法的含义
关于phpcms中模块_tag.class.php中的pc_tag()方法的含义: 在phpcms系统中自己写后台模块,要在前台模板中显示出来须要在\phpcms\modules\自定义 ...
- 快速构建Windows 8风格应用23-App Bar概述及使用规范
原文:快速构建Windows 8风格应用23-App Bar概述及使用规范 本篇博文主要介绍App Bar概述.App Bar命令组织步骤.App Bar最佳实践. App Bar概述 Windo ...
- 【COCOS2DX-游戏开发之三四】cocos2dx 3.0 TableView特殊使用方法:滚动时不能选择等等
cocos2dx 3.0版本号TableView拍生自ScrollView,经常使用来做滚动列表,有几种特殊使用方法,不知道大家用到过没 要求:1.滚动时不能选中TableCell,非滚动状态才干选中 ...
- WEB浏览器与服务器通讯过程
以访问网页www.baidu.com为例,下面是使用Wireshark捕捉到的数据: 浏览器先发起一个TCP连接,然后发送GET报文给服务器,服务器之后返回一个Response报文. 从服务器端返回时 ...
- ubuntu新内核不能用启动回滚到旧内核的方法
先看一看自己电脑上有哪些内核文件 merlin@tfAnalysis:~$ dpkg --get-selections|grep linux libselinux1:i386 install linu ...