javascript中的事件冒泡、事件捕获和事件执行顺序

谈起JavaScript的 事件,事件冒泡、事件捕获、阻止默认事件这三个话题,无论是面试还是在平时的工作中,都很难避免。

DOM事件标准定义了两种事件流,这两种事件流有着显著的不同并且可能对你的应用有着相当大的影响。这两种事件流分别是捕获和冒泡。和许多Web技术一样,在它们成为标准之前,Netscape和微软各自不同地实现了它们。Netscape选择实现了捕获事件流,微软则实现了冒泡事件流。幸运的是,W3C决定组合使用这两种方法,并且大多数新浏览器都遵循这两种事件流方式。

1事件传播——冒泡与捕获

  默认情况下,事件使用冒泡事件流,不使用捕获事件流。然而,在Firefox和Safari里,你可以显式的指定使用捕获事件流,方法是在注册事件时传入useCapture参数,将这个参数设为true。

概念:

事件冒泡:事件最开始由最具体的元素接收(文档层次中嵌套最深的那个节点),然后逐级向上传播最不具体的节点(document)。

事件捕获:事件由最不具体的元素接收,最后传播至最具体的元素。

事件冒泡代码实例:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>事件冒泡</title>
</head>
<body>
    <div id="e">
        <input id="btn" type="button" value="按钮">
    </div>
    <script type="text/javascript">
        var e = document.getElementById(‘e‘);
        var btn = document.getElementById(‘btn‘);
        e.onclick = function (){
            alert("你点击了div");
        };
        btn.onclick = function(){
            alert("你点击了button");
        }
    </script>
</body>
</html>

当我点击了按钮时候,运行 --你点击了button ——你点击了div,这就是事件冒泡。

事件捕获代码:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>事件冒泡</title>
</head>
<body>
    <div id="e">
        <input id="btn" type="button" value="按钮">
    </div>
    <script type="text/javascript">
        var e = document.getElementById(‘e‘);
        var btn = document.getElementById(‘btn‘);
        e.addEventListener(‘click‘,function(){
            alert(‘你点击了div‘);
        },true);
        btn.addEventListener(‘click‘,function(){
            alert(‘你点击了button‘);
        },true);
    </script>
</body>
</html>

当我点击了按钮时候,运行 --你点击了div ——你点击了button,这就是事件捕获。

(1)冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。

IE 5.5: input -> div -> body -> document

IE 6.0: input -> div -> body -> html -> document

Mozilla 1.0: input -> div -> body -> html -> document -> window

事件冒泡见下图:

(2)捕获型事件(event capturing):事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定)。

事件捕获见下图:

(3)DOM事件流:同时支持两种事件模型:捕获型事件和冒泡型事件,但是,捕获型事件先发生。两种事件流会触及DOM中的所有对象,从document对象开始,也在document对象结束。

一般来说事件冒泡机制,用的更多一些,所以在IE8以及之前,IE只支持事件冒泡。IE9+/FF/Chrome这2种模型都支持,可以通过addEventListener((type, listener, useCapture)的useCapture来设定,useCapture=false代表着事件冒泡,useCapture=true代表着采用事件捕获。而不兼容W3C的浏览器(IE)用attachEvent()方法,此方法没有相关设置,不过IE的事件模型默认是在事件冒泡时执行的,也就是在useCapture等于false的时候执行,所以把在处理事件时把useCapture设置为false是比较安全,也实现兼容浏览器的效果。

2DOM事件流

DOM事件流我也不知道怎么解释,个人感觉就是事件冒泡和事件捕获的结合体,直接看图吧

DOM事件流:将事件分为三个阶段:捕获阶段、目标阶段、冒泡阶段。先调用捕获阶段的处理函数,其次调用目标阶段的处理函数,最后调用冒泡阶段的处理函数。

<script>

    window.onload = function(){
        var outA = document.getElementById("outA");
        var outB = document.getElementById("outB");
        var outC = document.getElementById("outC");  

        // 目标(自身触发事件,是冒泡还是捕获无所谓)
        outC.addEventListener(‘click‘,function(){alert("target");},true);

        // 事件冒泡
        outA.addEventListener(‘click‘,function(){alert("bubble1");},false);
        outB.addEventListener(‘click‘,function(){alert("bubble2");},false);

        // 事件捕获
        outA.addEventListener(‘click‘,function(){alert("capture1");},true);
        outB.addEventListener(‘click‘,function(){alert("capture2");},true);
    };

</script>

<body>
    <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
        <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
            <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
        </div>
    </div>
</body>

当点击outC的时候,依次打印出capture1-->capture2-->target-->bubble2-->bubble1。到这里是不是可以理解addEventListener(type,handler,useCapture)这个API中第三个参数useCapture的含义呢?useCapture=false意味着:将事件处理函数加入到冒泡阶段,在冒泡阶段会被调用;useCapture=true意味着:将事件处理函数加入到捕获阶段,在捕获阶段会被调用。从DOM事件流模型可以看出,捕获阶段的事件处理函数,一定比冒泡阶段的事件处理函数先执行。

3事件函数执行先后顺序

<script>

    window.onload = function(){
        var outA = document.getElementById("outA");
        var outB = document.getElementById("outB");
        var outC = document.getElementById("outC");  

        // 目标(自身触发事件,是冒泡还是捕获无所谓)
        outC.addEventListener(‘click‘,function(){alert("target2");},true);
        outC.addEventListener(‘click‘,function(){alert("target1");},true);

        // 事件冒泡
        outA.addEventListener(‘click‘,function(){alert("bubble1");},false);
        outB.addEventListener(‘click‘,function(){alert("bubble2");},false);

        // 事件捕获
        outA.addEventListener(‘click‘,function(){alert("capture1");},true);
        outB.addEventListener(‘click‘,function(){alert("capture2");},true);

    };

</script>

<body>
    <div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
        <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
            <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
        </div>
    </div>
</body>

点击outC的时候,打印顺序是:capture1-->capture2-->target2-->target1-->bubble2-->bubble1。由于outC是我们触发事件的目标对象,在outC上注册的事件处理函数,属于DOM事件流中的目标阶段。目标阶段函数的执行顺序:先注册的先执行,后注册的后执行。这就是上面我们说的,在目标对象上绑定的函数是采用捕获,还是采用冒泡,都没有什么关系,因为冒泡和捕获只是对父元素上的函数执行顺序有影响,对自己没有什么影响。如果不信,可以将下面的代码放进去验证。

此我们可以给出事件函数执行顺序的结论了:捕获阶段的处理函数最先执行,其次是目标阶段的处理函数,最后是冒泡阶段的处理函数。目标阶段的处理函数,先注册的先执行,后注册的后执行。

4阻止冒泡和捕获

默认情况下,多个事件处理函数会按照DOM事件流模型中的顺序执行。如果子元素上发生某个事件,不需要执行父元素上注册的事件处理函数,那么我们可以停止捕获和冒泡,避免没有意义的函数调用。前面提到的5种事件绑定方式,都可以实现阻止事件的传播。IE8以及以前可过 window.event.cancelBubble=true阻止事件的继续传播;IE9+/FF/Chrome通过event.stopPropagation()阻止事件的继续传播。

<script>
    window.onload = function(){
        var outA = document.getElementById("outA");
        var outB = document.getElementById("outB");
        var outC = document.getElementById("outC");
        // 目标
        outC.addEventListener(‘click‘,function(event){
            alert("target");
            if(event.stopPropagation){
                event.stopPropagation();
            }else{
                event.cancelBubble = true;//IE阻止事件冒泡,true代表阻止
            }
        },false);
        // 事件冒泡
        outA.addEventListener(‘click‘,function(){alert("bubble");},false);

        // 事件捕获
        outA.addEventListener(‘click‘,function(){alert("capture");},true);
    };
</script>
<div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
        <div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
            <div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
        </div>
    </div>

当点击outC的时候,之后打印出capture-->target,不会打印出bubble。因为当事件传播到outC上的处理函数时,通过stopPropagation阻止了事件的继续传播,所以不会继续传播到冒泡阶段。

原文链接:http://lib.csdn.net/article/javascript/6265?knId=505

时间: 2024-10-01 05:47:34

javascript中的事件冒泡、事件捕获和事件执行顺序的相关文章

事件冒泡与捕获&amp;amp;事件托付

设想这样一种情况 一个div里面有个span元素  ,当鼠标单击span时,这个事件算是谁的? div还是span? 准确的说两个都触发了,这种认可大家都允许,事实就是这种, 第二个问题来了,这个事件应该有个先后顺序 ,先触发span还是div? 早期就有两个主流的浏览器厂商各执己见,IE觉得,这个事件首先触发span,然后依次往父节点传递,终于传递到document,(这个过程称为冒泡) 网景浏览器觉得,不论什么事件都首先触发document,然后依次往下传递到span元素,(这个过程称为捕获

JavaScript权威设计--事件冒泡,捕获,事件句柄,事件源,事件对象(简要学习笔记十八)

1.事件冒泡与事件捕获 2.事件与事件句柄 3.事件委托:利用事件的冒泡技术.子元素的事件最终会冒泡到父元素直到跟节点.事件监听会分析从子元素冒泡上来的事件. 事件委托的好处: 1.每个函数都是对象,都会占用内存,内存中对象越多,性能越差. 2.必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间. 怎样处理由于事件较多引起的性能差: 1.采用事件委托技术,限制简历的连接数量 2.在不需要的时候移除事件处理程序 例子: html: <div id="myDiv&

关于dom 事件冒泡、捕获 dom事件三个阶段

本文主要解决两个问题: 什么是事件流 DOM事件流的三个阶段 起因 温故了一下我的<JavaScript高级程序设计>的时候,翻到DOM事件那一章,(说实话,现在无论是什么框架你都离不开操作DOM啊,毕竟这是你展示的最基本元素,就像人的细胞).想起了dom事件流原理,好多人不明白,只知道click mouseout等实用场景,真要理解和更进一步的前端是要必须:理论+实践 并行的. 当然,DOM事件所囊括的知识较为庞杂,所以本文专注与自己学习时所碰到的难点,DOM事件流. 流 流的概念,在现今的

JavaScript事件冒泡与捕获

event.preventDefault();    如果event.cancelable的值为true,可以取消默认事件 event.cancelable;             元素是否可以取消默认事件,true可以取消,false不可以取消,IE8不支持 event.cancelBubble;         true:设置当前事件不冒泡,false:设置当前事件冒泡 event.stopPropagation();  停止当前事件的分发,不论当前事件是在冒泡还是在捕获阶段 事件--怎样

整理之DOM事件阶段、冒泡与捕获、事件委托、ie事件和dom模型事件、鼠标事件

整理之DOM事件阶段 本文主要解决的问题: 事件流 DOM事件流的三个阶段 先理解流的概念 在现今的JavaScript中随处可见.比如说React中的单向数据流,Node中的流,又或是今天本文所讲的DOM事件流.都是流的一种生动体现.用术语说流是对输入输出设备的抽象.以程序的角度说,流是具有方向的数据. 事件流分事件冒泡与事件捕获 在浏览器发展的过程中,开发团队遇到了一个问题.那就是页面中的哪一部分拥有特定的事件? 可以想象画在一张纸上的一组同心圆,如果你把手指放在圆心上,那么你的手指指向的其

事件冒泡与捕获

事件流指的是页面中接收事件的顺序,IE,火狐和chrome浏览器都是事件冒泡,所谓是事件冒泡指的是事件最开始由最具体的元素接收,然后逐级向上传播到不具体的节点.而事件捕获则正好相反,事件捕获是由Netscape提出的,事件冒泡和捕获具体如下图所示: 虽然事件捕获是Netscape唯一支持的事件流模型,但目前IE9,火狐和谷歌也都支持这种事件流模型. 事件冒泡的好处 因为事件具有冒泡机制,因此我们可以利用冒泡的原理,把事件加到父级上,触发执行效果.这样做的好处当然就是提高性能了. 如果说我们可能有

事件流,冒泡,捕获,事件委托

js里怎么去监听一个事件? 网页中每一个元素都有可以产生某些触发JavaScript函数的事件,事件是可以被JavaScript侦测到的一种行为 监听方法的参数分别代表什么意思?其中哪些参数关系到js的事件流机制?js事件流机制有哪些工作?工作原理是什么? 第一个参数是,事件类型,例如onclick 第二个参数是,响应的时候所执行的函数 第三个是事件流问题,侦听的三个阶段,捕获阶段 --- 目标阶段 --- 冒泡阶段 此处的参数确定侦听器是运行于捕获,目标还是冒泡 如果将useCapture设置

[JS]笔记12之事件机制--事件冒泡和捕获--事件监听--阻止事件传播

-->事件冒泡和捕获-->事件监听-->阻止事件传播 一.事件冒泡和捕获 1.概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的onclick事件也会被触发.js里称这种事件连续发生的机制为事件冒泡或者事件捕获.IE浏览器:事件从里向外发生,事件从最精确对象(target)开始触发,然后到最不精确的对象(document)触发,即事件冒泡 Netscape:事件从外向里发生,事件从最不精确的对象(document)开始触发,然后到最精确对象(

JS 事件冒泡、捕获。学习记录

作为一个转行刚到公司的新人,任务不多,这一周任务全部消灭,闲暇的一天也别闲着,悄悄的看起了书.今天写一下JS的事件冒泡.捕获. 也是今天看的内容有点多了,有些消化不了,就随手记录一下.纯属自我理解,如果有不对,还请指导提出,小弟一定改正. 好了,话不多说.那么事件冒泡是什么? 举个例子 ul > li > div > p . 这个时候你点击P,他会一层一层的往上执行,直到最后绑定事件的元素.假如我们绑定事件在ul上,那么点击P,他就会逐级往上走,直到找到绑定事件的ul也会触发事件,那么在

小程序事件的介绍、事件对象、事件传值、事件冒泡和捕获

小程序在1.5版本以后,支持  bind:tap=“事件名称”  来绑定事件 catch:tap=“事件名称”    也可以用catchtap来绑定事件 还有一些几乎所有组件都有的事件: touchstart:手指开始触摸 touchmove:手指移动 touchcancel:手指触摸被打断,比如说电话来了 touchend:手指停止触摸 tap:手指触摸后马上离开  相当于js中的click点击事件 longpress:长按  且长按事件超过350毫秒 longtap:长按 超过350毫秒再离