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

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

时间: 2024-09-11 04:13:36

由点击页面其它地方隐藏div所想到的jQuery的delegate_jquery的相关文章

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

实例如下: <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的两种思路_javascript技巧

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

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

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

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

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

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

复制代码 代码如下: <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

js 点击页面其他地方关闭弹出层

<!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> <meta http-equiv="Content-

如何重新加载页面中指定的DIV?

问题描述 页面中包含隐藏DIV,是个弹出层,新建/修改共用的一个表单,有部分下拉框的数据是页面加载时从后台获取的.在页面点击修改,数据渲染到这个DIV中,并弹出.然后不做任何操作直接关闭弹出层.再点击新建时,由于前面的数据未清除,所以老数据直接被带出来了.DIV的弹出和隐藏都是用简单的show和hide.因为"修改--关闭"操作并没有提交表单数据,所以如果用reload会不友好.我想请问下有什么办法可以清除数据或者重新加载这部分页面内容.谢谢 问题补充:嗯,刚想到个笨办法,div隐藏的

关于隐藏div伴随屏幕呈现问题 在线等

问题描述 我想实现一个效果就是有一个隐藏div我的屏幕在滚动当我点击触发显示这个隐藏div时div是停留在当前页面的中间的这个效果要在ie6下实现 解决方案 解决方案二:没人么这个帖子解决方案三:停留在中间这个应该需要前台的一些浮动啊什么的都忘玩了解决方案四:引用楼主u012765139的回复: 我想实现一个效果就是有一个隐藏div我的屏幕在滚动当我点击触发显示这个隐藏div时div是停留在当前页面的中间的这个效果要在ie6下实现 ie6有点不好整吧?解决方案五:可以使用js控制实现!

div-点击DIV外任意地方隐藏此DIV 或点击iframe子页面中隐藏 父页面DIV

问题描述 点击DIV外任意地方隐藏此DIV 或点击iframe子页面中隐藏 父页面DIV <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> <script src="http://www.p