首页 > JavaScript > jQuery事件,扣动扳机(二)
2009四月19

jQuery事件,扣动扳机(二)

两天没有正经更新博客了,这里似乎已经有了一丝荒芜的味道。

原因嘛,很简单,我的电脑被霸占了,因为丫头的同学来了,总不能我吭吃吭吃的占着电脑不撒手赖在屋里不走啊。。哈。

闲话不说了,写一下上回未完成的事业,js中“事件的旅程”。

当页面上发生一个事件时,每个层次上的DOM元素都有机会处理这个事件。


以下面代码为例(书中给出的)

<div class="div_xiaozi">
    <span class="span_xiaozi">
        <a href="http://www.xiaoxiaozi.com/" target="_blank" class="a_xiaozi">小小子欢迎您</a>
    </span>
    <p class="p_xiaozi">
        这里至少还有我,小小子,存在~
    </p>
</div>

当在浏览器中形象化地呈现这些由嵌套的代码构成的元素时,我们看到的效果其实是这样的。

自己画的HTML代码的DOM图

自己画的HTML代码的DOM图

举例来说,如果单击了页面中的超链接(锚元素),那么<div>、<span>和<a>全都应该得到响应这次单击的机会。

因为这三个元素毕竟都是在用户的鼠标指针之下啊。那么,最终响应的效果是什么样的呢?

在事件捕获的过程中,事件首先会交给最外层的元素,接着再交给更具体的元素。

事件捕获

事件捕获

在事件冒泡中,当事件发生时,会首先发送给最具体的元素,在这个元素获得响应机会之后,事件会向上冒泡至更一般的元素。

事件冒泡

事件冒泡

那么,什么浏览器采用的是“事件捕获”模式,而又有哪些采用的是“事件冒泡”模式呢?

其实,最终出台的DOM标准规定应该同时使用这两种策略:首先,事件要从一般到具体进行捕获,钴,事件再通过冒泡返回DOM树的顶层。而事件处理可以注册到这个过程中的任何一部分。即,可以把事件处理程序注册到事件捕获阶段,也可以注册到事件冒泡阶段。

但是,遗憾的通知大家,浏览器厂商,并不是这么做的。。

FF运载标准事件模型(即同时支持捕获和冒泡),要把事件处理注册到捕获阶段,必须在标准的事件注册方法addEventListener()中将最后一个参数设置为true。
IE的事件注册方法attachEvent()只能将事件处理程序注册到冒泡阶段。
为了提供跨浏览器兼容性,jQuery始终会在模型的冒泡阶段注册事件处理程序(即为了和IE兼容啊。。),因此,我们总是可以假定最具体的元素会首先获得响应事件的机会。

现在我们了解了jQuery的事件处理方式,那么我们来想一想,这种方式会给我们带来什么?惊喜?NO,惊讶与麻烦。。

因为“事件冒泡”可能会导致我们预想不到的事情发生,比如,错误的元素响应mouseover或mouseout事件的情况下。

.div_xiaozi{border:1px solid red;}
    $(document).ready(function(){
        $(".a_xiaozi").mouseout(function(){
            alert("鼠标从超链接上走出来喽");
        });
        $(".span_xiaozi").mouseout(function(){
            alert("鼠标从SPAN上走出来喽");
        });
        $(".p_xiaozi").mouseout(function(){
            alert("鼠标从P上走出来喽");
        });
        $(".div_xiaozi").mouseout(function(){
            alert("鼠标从DIV上走出来喽");
        });
    });

你会发现,当你的鼠标从<a><span><p>标签上面出来的时候在最后都会alert”鼠标从DIV上走出来喽”这句话

是不是很烦,为什么?方法冒泡啦,从最里层向外,咕嘟咕嘟的冒到外面来了。。

不过.hover()方法能够聪明地处理这些冒泡问题(指mouseout(),mouseover()这两个方法导致的冒泡问题),当我们使用该方法添加事件时,可以不必考虑由于错误的元素取得mouseout或mouseover事件而导致的问题。这就使得.hover()成为绑定个别鼠标事件的一种有吸引力的替代方案。

那么我们怎么阻止事件冒泡呢?

其实导致这个问题的根本原因就是冒泡,把本应该在正确元素上面发生的事件又传递给外层DOM,让外层DOM也去响应这个事件。

所以我们应该访问“事件对象”。

事件对象是一种JS结构,它会在元素获得处理事件的机会时被传递给相应的事件处理程序。这个对象中包含着与事件有关的信息(例如事件发生时的鼠标指针位置),也提供了可以用来影响事件在DOM中传递进程的一些方法。
为了在处理程序中使用事件对象,需要为函数添加一个参数:event

说到event,我就要发表一下个人意见,这个参数是我非常烦的一个东西,因为我不了解-_-!!!,而对一个东西不了解就导致你不会用它,所以它经常给我带来不小的麻烦。

    $(document).ready(function(){
        $(".p_xiaozi").mouseout(function(event){
            alert("鼠标从P上走出来喽");
        });
    });

事件处理程序中的变量event保存着事件对象,而event.target属性保存着发生事件的目标元素(也就是真正应该对事件做出响应的DOM元素)

虽然这个event.target是DOM API中规定的,不过IE并没有实现哦。IE把事件对象保存在了全局属性window.event中,而事件目标则可以通过window.event.srcElement属性访问到
但是jQuery中则不用考虑这些差别,因为其对这些进行了必要的扩展,从而晨任何浏览器中都能够使用这个属性(event.target)

我们知道,this引用的是处理事件的DOM元素,所以可以编写下面的代码

    $(document).ready(function(){
        $(".p_xiaozi").mouseout(function(event){
            if(event.target == this)
            {
                alert("鼠标从P上走出来喽");
            }
        });
    });

这样就能保证鼠标移出<a>标签的时候只alert(“鼠标从超链接上走出来喽”);而不会把这个事件(mouseout)传递到外层DOM标签中去。

难道只有这一种方法解决事件冒泡带来的难题?NO,还有一种更绝的方法,那就是。。。“停止事件传播”。。

事件对象还提供一个.stopPropagation()方法,可以完全阻止事件冒泡。与.target类似,这个方法也是一种纯JS特性,但是在跨浏览器环境中则无法安全的使用(即在IE中停止冒泡应该使用事件对象的cancelBubble属性设置为false),不过通过jQuery来注册所有的事件处理程序,就可以放心地使用这个方法。

    $(document).ready(function(){
        $(".p_xiaozi").mouseout(function(event){
            alert("鼠标从P上走出来喽");
            event.stopPropagation();
        });
    });

既然说了这么多,那么也不在乎在来点内容了,那就是阻止事件的默认操作。

什么是默认操作?举个最简单的例子就可以说明白了,点击<a>标签就会将浏览器引向一个新的链接。点击submit标签,就会提交表单。

那么怎么阻止这些默认操作呢?我用的最简单的方法就是return false;

如果我们不希望执行这种默认操作,那么在事件对象上调用.stopPropagation()方法也无济于事,因为默认操作不是在正常的事件传播流中发生的。在这种情况下,.preventDefault()办法则可以在触发默认操作之前终止事件。(在IE中要想预防默认操作发生,需要将事件对象的returnValue属性设置false)

事件传播和默认操作是相互独立的两套机制,在二者任何一方发生时,都可以终止另一方,如果想要同时停止事件传播和默认操作,可以在事件处理程序中返回false,这是对在事件对象上同时调用.stopPropagation()和.preventDefault()的一种简写方式。。。

PS:虽然写这么多(抄这么多好不好??)有点累,不过,嘿嘿。。留个备忘总是好的。。

如果有不明白“事件冒泡”的可以去如果你还不理解JavaScript的事件冒泡去看一下,示例写的很好。

文章作者:simaopig
本文地址:http://www.xiaoxiaozi.com/2009/04/19/189/
版权所有 © 转载时必须以链接形式注明作者和原始出处!

11 Responses to “jQuery事件,扣动扳机(二)”

  1. #1 HKH.Lucifer 回复 | 引用 Post:2009-04-20 13:01

    这主题太多人用了~!~

    [回复]

  2. #2 simaopig 回复 | 引用 Post:2009-04-20 13:21

    @HKH.Lucifer
    呵,是啊。相当多的人。。“用烂了”。不过,我还是蛮喜欢这个的。呵。

    [回复]

  3. #3 月夜 回复 | 引用 Post:2009-04-20 18:47

    呵呵。。写的好专业。。而且也是专业人士哈。。不过月夜都不懂。。
    PS:看到你的版权声明:“否则保留追究法律责任的权利。”
    感觉貌似也是一种无奈哈。。哈哈。。

    [回复]

  4. #4 小明猪 回复 | 引用 Post:2009-04-20 18:57

    我怎么感觉前几天就看见你这里就有这文章?难道是幻觉?
    这两天我到处跑,也没时间停下来更新下博客嘞,大家都在努力

    [回复]

  5. #5 simaopig 回复 | 引用 Post:2009-04-20 19:17

    @小明猪
    嘿嘿,几天前的在这里啊jquery事件,扣动扳机(一)
    这个是(二)
    在外面跑?散心吗?

    [回复]

  6. #6 wulinfo 回复 | 引用 Post:2009-04-20 19:29

    理解有限,只能留点垃圾就走人啦

    [回复]

  7. #7 simaopig 回复 | 引用 Post:2009-04-20 20:53

    @月夜
    呵,才进后台看到你的留言。
    哈,其实版权声明就是瞎写的。说到追究法律哪能啊?我可没那时间。
    就是希望如果有人转载的话好歹提一下我,毕竟是自己的汗水哈。

    [回复]

  8. #8 simaopig 回复 | 引用 Post:2009-04-20 20:54

    @wulinfo
    呵,不带这么说话的哈。你能来,我很开心。
    貌似你好几天没来了,交的是朋友。我写的其实也很浅,会被真正的高手骂死的。
    术业有专攻,这些只是我的学习笔记而已啦。
    没事常来。你是我的朋友。^_^

    [回复]

  9. #9 alswl 回复 | 引用 Post:2010-02-08 09:53

    Ajax in Action
    哇咔咔

    [回复]

  10. #10 xinem 回复 | 引用 Post:2010-02-22 20:54

    不错,最近在学jQuery,你这篇写的很好理解,感谢。

    [回复]

  11. #11 simaopig 回复 | 引用 Post:2010-02-23 10:27

    @xinem
    呵,见笑,大多数都是书中的语言,把之换为普通话罢了。

    感谢您的来访。 :smile:

    [回复]

发表评论

:wink: :twisted: :roll: :oops: :mrgreen: :lol: :idea: :evil: :cry: :arrow: :?: :-| :-x :-o :-P :-D :-? :) :( :!: 8-O 8)