由点击页面其它地方隐藏div所想到的jQuery的delegate

先从最简单的开始,假如页面有一个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,看看是否对提高性能有所帮助。

(0)

相关推荐

  • JQuery控制div外点击隐藏而div内点击不会隐藏的方法

    本文实例讲述了JQuery控制div外点击隐藏而div内点击不会隐藏的方法.分享给大家供大家参考.具体如下: 比如有个div其id为body,实现在div外点击隐藏,div内点击不隐藏,采用jQuery实现如下: 复制代码 代码如下: $("#body").click(function(e) {      $(this).show();          e.stopPropagation();  });  $(document).click(function(event) {   

  • JQuery实现点击div以外的位置隐藏该div窗口

    jquery实现鼠标点击div外的地方div窗口隐藏消失的 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <he

  • jquery实现点击展开列表同时隐藏其他列表

    本文实例讲述了jquery实现点击展开列表同时隐藏其他列表.分享给大家供大家参考.具体如下: 这里使用jquery实现展开.隐藏特效,点击列表标题后该项内容展开,其它项收缩起来,也就是不显示了.个人喜好了,有的喜欢在默认状态下不显示其它选项的内容,这个就是这种情况,仅供参考吧. 运行效果截图如下: 具体代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o

  • Jquery实现点击切换图片并隐藏显示内容(2种方法实现)

    我们的电脑屏幕大小是固定的,那么如何在有限的空间放更多的内容呢? 我们应该给用户足够的选择权,当他们想要看某些内容的时候可以很快的看到,不想看的时候就把他隐藏.于是就有了题目说的这个问题. 其实这个问题很简单,那么,之所以拿出来跟大家分享,一方面我们大家相互交流,另一方面,也是对自己的学习的一种总结. 这里我想到了两种方法,给大家分享一下. 好了不多说,下面看代码: 第一种,是常规的方法: [javascript] 复制代码 代码如下: $(function(){ var images = ['

  • Jquery 点击按钮显示和隐藏层的代码

    代码: 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"

  • 基于jquery鼠标点击其它地方隐藏层的实例代码

    效果图:下面的代码运行后,需要再刷新一下. test .div_d{ padding:10px; border:1px dotted red; position:absolute; display:none; cursor:pointer;} $(function(){ $("input[id=search]").focus(function(even){ var pos=$(this).offset(); $(".div_d").css({left:pos.lef

  • jquery实现点击其他区域时隐藏下拉div和遮罩层的方法

    本文实例讲述了jquery实现点击其他区域时隐藏下拉div和遮罩层的方法.分享给大家供大家参考,具体如下: 为了更好的用户体验,在做下拉获取其他有弹出层的时候,当展开下拉时,要做到点击其他区域也能自动隐藏收起下拉和遮罩层,这样的效果用一段js就可以了. 以下图为例的一个下拉菜单为参考: 效果实现源码: $(document).bind('click', function(e) { var e = e || window.event; //浏览器兼容性 var elem = e.target ||

  • jquery特效 点击展示与隐藏全文

    本文实例讲述了jquery点击展示与隐藏全文特效,这里使用jquery实现展开.隐藏特效,点击查看全文后内容展开,点击收起全文其内容收缩,分享给大家供大家参考.具体如下: 运行效果截图如下: 具体代码如下 一.来看一下主体框架程序: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>点击查看全文</title> <link type=&

  • 基于JQuery实现鼠标点击文本框显示隐藏提示文本

    比如本人网站的搜索框: 不使用的时候: 鼠标点击后: 用JQuery实现这个效果非常简单,下面是代码: 复制代码 代码如下: $(document).ready(function () { var searchBox = $("#ctl00_txtSearch"); searchBox.focus(function () { if (searchBox.val() == this.title) { // TextBox控件ToolTip属性转换为Html为title属性 searchB

  • 由点击页面其它地方隐藏div所想到的jQuery的delegate

    先从最简单的开始,假如页面有一个id为test的div,我们要实现点击页面其它地方隐藏该div: 复制代码 代码如下: <div id="test" style="margin:100px;background-color:#3e3;width:100px;height:100px;"> </div> 对于这个问题一般有两种思路,这两种思路都会利用事件冒泡这一原理,想要详细了解Javascript事件机制可以看看JavaScript与HTML

  • 点击页面任何位置隐藏div的实现方法

    实例如下: <include file="Public:header" /> <style type="text/css"> table{width:100%;margin: 0;} </style> <script type='text/javascript' src="/{:APP_PATH}/Public/js/unslider.min.js"></script> <scri

  • 点击页面其它地方隐藏该div的两种思路

    思路一 第一种思路分两步 第一步:对document的click事件绑定事件处理程序,使其隐藏该div 第二步:对div的click事件绑定事件处理程序,阻止事件冒泡,防止其冒泡到document,而调用document的onclick方法隐藏了该div. 复制代码 代码如下: <script type="text/javascript"> function stopPropagation(e) { if (e.stopPropagation) e.stopPropagat

  • jQuery除指定区域外点击任何地方隐藏DIV功能

    具体代码如下所示: $('body').click(function(e) { var target = $(e.target); // 如果#overlay或者#btn下面还有子元素,可使用 // !target.is('#btn *') && !target.is('#overlay *') if(!target.is('#btn') && !target.is('#overlay')) { if ( $('#overlay').is(':visible') ) { $

  • jQuery点击页面其他部分隐藏下拉菜单功能

    一.开发小要点 web页面中,我们一般不用select.option来实现下拉菜单效果,因为下拉框的样式丑且难以美化,所以我们选择控制ul显示隐藏来实现同样且高大上的效果,但是不能像下拉框那样点击页面其他部分,下拉菜单收起或隐藏,该怎么办呢?只能用js这老大哥来控制了. 二.代码 HTML: <div class="select_box" id="selected"> <div class="select"> <sp

  • js点击页面其它地方将某个显示的DIV隐藏

    实现也很简单,但需要注意的是,在点击显示的事件中,需要做阻止事件冒泡的处理,否则就触发页面的点击事件了.但这样做也有一个缺点,即如果同一个页面中如果也有事件阻止冒泡,则不能隐藏DIV,所以在这样的事件中需要特殊处理下:自己调用隐藏下DIV(但正常来说这样的事件并不多): JS: 复制代码 代码如下: $(document).ready(function() { //语言头部的点击事件,显示语言列表 $(".language_selected").click(function(e) {

  • Javascript点击其他任意地方隐藏关闭DIV实例

    代码如下,实现了点击input显示一个div层,当点击除input和div以外的地方的时候,隐藏div的功能. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>点击其它地方关闭DIV</title> </head> <body> <input type="text" value="

  • js 点击页面其他地方关闭弹出层(示例代码)

    复制代码 代码如下: <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> <style type="text/css"> <!-- *{font-size:12px;font-family:Verdana, Gen

  • Vue实现点击当前元素以外的地方隐藏当前元素(实现思路)

    1. 绑定元素 2. mounted生命周期 3. 实现思路 页面挂载完后,监听全局点击事件 获取当前点击的元素,根据需求获取当前元素本身的属性 判断当前点击元素与要隐藏的元素是否相同 当前点击元素与要隐藏的元素不相同则隐藏 4. 最终效果 接着看下vue实现点击目标元素外页面的其他地方隐藏弹窗 方法: 步骤1:给页面最外出的元素div加点击事件:@click="popShow = false". 步骤2:给点击目标元素加点击事件:@click="popShow = true

  • Vue实现 点击显示再点击隐藏效果(点击页面空白区域也隐藏效果)

    平时项目中,经常会做一些下拉菜单等效果,这种效果可能会需要通过一个按钮来控制显示隐藏,并且当点击页面其他空白区域时,也要将其隐藏. 简单写个Demo <!-- 按钮 --> <button @click.stop="ShowHidden = !ShowHidden">显示或隐藏</button> <!-- 下拉列表 --> <div v-if="ShowHidden" @click.stop="&quo

随机推荐