谈起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

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

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

    设想这样一种情况 一个div里面有个span元素  ,当鼠标单击span时,这个事件算是谁的? div还是span? 准确的说两个都触发了,这种认可大家都允许,事实就是这种, 第二个问题来了,这个事件 ...

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

    1.事件冒泡与事件捕获 2.事件与事件句柄   3.事件委托:利用事件的冒泡技术.子元素的事件最终会冒泡到父元素直到跟节点.事件监听会分析从子元素冒泡上来的事件. 事件委托的好处:     1.每个函 ...

  3. JavaScript事件冒泡与捕获

    event.preventDefault();    如果event.cancelable的值为true,可以取消默认事件 event.cancelable;             元素是否可以取消 ...

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

    整理之DOM事件阶段 本文主要解决的问题: 事件流 DOM事件流的三个阶段 先理解流的概念 在现今的JavaScript中随处可见.比如说React中的单向数据流,Node中的流,又或是今天本文所讲的 ...

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

    -->事件冒泡和捕获-->事件监听-->阻止事件传播 一.事件冒泡和捕获 1.概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的oncl ...

  6. js事件机制——事件冒泡和捕获

    概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的onclick事件也会被触发.js里称这种事件连续发生的机制为事件冒泡或者事件捕获. IE浏览器:事件从 ...

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

    作为一个转行刚到公司的新人,任务不多,这一周任务全部消灭,闲暇的一天也别闲着,悄悄的看起了书.今天写一下JS的事件冒泡.捕获. 也是今天看的内容有点多了,有些消化不了,就随手记录一下.纯属自我理解,如 ...

  8. DOM事件-冒泡、捕获、传播、委托

    事件捕获 以点击事件为例事,同类型事件会由根元素开始触发,向内传播,一直到目标元素.从外到内依次触发:根—目标的祖先素—目标的父元素—目标元素. 事件冒泡 根事件捕获截然相反.发生点击事件时,事件会从 ...

  9. JavaScript 中的内存和性能、模拟事件(读书笔记思维导图)

    由于事件处理程序可以为现代 Web 应用程序提供交互能力,因此许多开发人员会不分青红皂白地向页面中添加大量的处理程序.在 JavaScript 中,添加到页面上的事件处理程序数量将直接关系到页面的整体 ...

  10. JS 事件冒泡整理 浏览器的事件流

    JavaScript与HTML的交互通过事件来实现.而浏览器的事件流是一个非常重要的概念.不去讨论那些古老的浏览器有事件捕获与事件冒泡的争议, 只需要知道在DOM2中规定的事件流包括了三个部分,事件捕 ...

随机推荐

  1. yii2输出sql语句

    yii2如何输出具体的查询的sql语句: $query = User::find() ->where(['id'=>[1,2,3,4]) ->select(['username']) ...

  2. node平台截取图片模块——jimp

    前几天介绍了一个简单的截图模块——iamges,虽然简单,但是功能还是有很多局限的地方. jimp的优势:1.简单,2.支持回调方式和ES6(promise)语法也可以链式调用 3. 丰富的api   ...

  3. HttpEntity转换Inputstream(红色)加XmlPull解析

    package com.bawei.xml; import java.io.IOException; import java.io.InputStream; import java.util.Arra ...

  4. DataGridView

    一.实现CheckBox列. 1.1 增加CheckBox列: 在DataGridView中增加CheckBox列: 注意:设置ColumnType类型和设置FalseValue为0,TrueValu ...

  5. 基于bootstrap 的datatable插件的使用2(php版)

    DataTables 中有两种不同的方式处理数据(排序.搜索.分页等): 客户端处理(Client)-- 所有的数据集预先加载(一次获取所有数据),数据处理都是在浏览器中完成的[逻辑分页]. 服务器端 ...

  6. CI 框架导出文件

    CI框架目录结构: |-application (应用目录) |-system (核心目录) |-downexcel (文件存在目录) |-ZipBackDir (备份目录) |-index.php ...

  7. JavaScript简介

    JavaScript JavaScript 是一种轻量级的编程语言,是可插入 HTML 页面的编程代码,这门语言可用于 HTML 和 web,更可广泛用于服务器.PC.笔记本电脑.平板电脑和智能手机等 ...

  8. NOI 动态规划题集

    noi 1996 登山 noi 8780 拦截导弹 noi 4977 怪盗基德的滑翔翼 noi 6045 开餐馆 noi 2718 移动路线 noi 2728 摘花生 noi 2985 数字组合 no ...

  9. 三元运算与lambda表达式

    #三元运算,就是对if else的简写 if 1 == 1: print("jasper") else: print("sb") 三元运算写法 name=&qu ...

  10. asp.net type=file在上传图片到服务器

    前台 <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> ...