转自:http://www.cnblogs.com/dolphinX/p/3239530.html
在网页开发的过程中经常遇到的一个需求就是点击一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,看看是否对提高性能有所帮助。
相关推荐
这就是标题中提到的需求——点击页面其他地方隐藏div。在这种情况下,jQuery的`delegate`方法可以派上用场,它允许我们在文档或者父元素上监听事件,而不是直接在每个可能的目标元素上绑定事件处理器。 首先,让...
在jQuery中,`delegate()` 是一个非常有用的函数,它允许我们为页面上当前存在或将来可能存在的元素绑定事件处理程序。这个方法对于处理动态生成的DOM元素尤其有用,因为它们在文档加载时并不存在,因此无法直接使用...
jQuery的核心之一是其强大的CSS选择器支持,包括ID选择器 (#id)、类选择器 (.class)、元素选择器 (element) 等,甚至支持组合选择器和伪类,如 $(“div.special”).find(“p:first”),可以高效地定位到页面中的特定...
这里,我们绑定了一个全局的点击事件,当用户点击页面上的任何地方时,`hide()`函数会被调用。`hide()`函数会检查点击事件是否源自特定元素或其子元素,然后根据判断结果执行相应操作。 `hide()`函数内部的实现可能...
1. 模态对话框:使用jQuery创建可复用的模态对话框,利用`.show()`和`.hide()`控制显示与隐藏。 2. 数据表格:结合jQuery和插件如DataTables,实现分页、排序和过滤功能。 3. 表单验证:结合jQuery Validation插件,...
- **减少DOM操作**:尽可能使用jQuery的`$(...).delegate()`或`$(...).on()`来绑定事件,减少DOM遍历。 ### 6. 兼容性和版本选择 jQuery Mobile 支持主流的现代浏览器,包括Chrome、Firefox、Safari以及IE9+。对于...
jQuery 1.3之后,jQuery继续发展,推出了1.x系列的更多版本,逐步加入了更多的特性,如`.delegate()`和`.undelegate()`,以及后来的`.on()`和`.off()`等方法。同时,jQuery 2.x版本放弃了对IE6/7的支持,进一步提升...
《jQuery基础自学笔记》 jQuery 是一款非常流行的 JavaScript 库,由 John Resig 在2006年创建,它的出现极大地简化了JavaScript的DOM操作、事件处理、动画设计以及Ajax交互。jQuery 的设计理念是“Write Less, Do ...
如果您的网站包含许多页面,并且您希望您的 jQuery 函数易于维护,那么请把您的 jQuery 函数放到独立的 .js 文件中。 当我们在教程中演示 jQuery 时,会将函数直接添加到 <head> 部分中。不过,把它们放到一个单独的...
在jQuery库中,`delegate()`方法是一个非常有用的事件处理函数,尤其在处理动态添加的DOM元素时。这个方法允许我们为指定元素的后代元素添加事件监听器,即使这些后代元素在`delegate()`调用时还不存在。这种方法...
在这个项目中,我们将使用jQuery来控制图片的显示和隐藏,以及添加缩略图功能,使用户可以通过点击缩略图来切换大图。 1. **引入jQuery库**: 首先,确保HTML文档中正确引入jQuery库。由于提示不要使用高于1.6的...
`bind()`、`unbind()`、`live()`和`delegate()`也是常见的事件处理方法,但自jQuery 1.7开始,推荐使用统一的`on()`和`off()`来管理事件。 五、动画效果 jQuery的动画功能强大,`slideUp()`, `slideDown()`, `...
- **模块化**:使用AMD(Asynchronous Module Definition)或CMD(Common Module Definition)规范,如RequireJS,实现jQuery的按需加载,减少页面初始化时的负担。 - **插件使用**:jQuery拥有丰富的第三方插件...
`.bind()`, `.live()`, `.delegate()` 和 `.on()` 也是常见的事件绑定方法,其中 `.on()` 是1.7版本引入的,可替代其他几个方法,提供更灵活的事件处理方式。 ### 4. 动画效果 jQuery 的动画功能是其另一大亮点。`...
这意味着一旦获取了一个jQuery对象,可以连续调用其方法,每个方法都会返回一个jQuery对象,除非明确返回其他类型的结果。例如:`$("p").css("color", "red").hide()`,这会将所有段落的颜色设为红色,然后隐藏它们...
在这个实例中,我们讨论的是如何利用jQuery来实现一个特定的交互功能,即点击不同的div元素时,控制一个弹出层(layer)的显示与隐藏,同时处理好事件冒泡的问题。 首先,我们需要理解事件冒泡的概念。在DOM结构中...
10. **性能优化**:手册还会涵盖如何使用`live()`, `delegate()`, `on()`等方法来提高事件处理性能,以及如何避免不必要的DOM操作以提升页面性能。 通过这份《jQuery 1.5.2 CHM中文手册》,开发者不仅可以学习到...
例如,`$('div').slideUp(500)`会在500毫秒内将div向上滑动隐藏。 六、Ajax请求 jQuery的Ajax功能使得异步数据交互变得简单。`.ajax()`是核心方法,支持GET和POST等多种请求类型。`.getJSON()`和`.getScript()`...
- **选择器**:jQuery支持CSS1-CSS3选择器,以及自定义的jQuery选择器,如`$("div.myClass")`可以轻松选取所有class为myClass的div元素。 - **DOM操作**:可以方便地进行元素的添加、删除、修改,如`$("#element")...
《jQuery API 1.4(中文)》及jQuery 1.4.2详解 jQuery,一个广泛应用于Web开发的JavaScript库,以其简洁易用的API和强大的功能深受开发者喜爱。本指南将深入探讨《jQuery API 1.4(中文)》及jQuery 1.4.2版本中的...