javascript中的事件冒泡、事件捕获和事件执行顺序
谈起JavaScript的 事件,事件冒泡、事件捕获、阻止默认事件这三个话题,无论是面试还是在平时的工作中,都很难避免。
DOM事件标准定义了两种事件流,这两种事件流有着显著的不同并且可能对你的应用有着相当大的影响。这两种事件流分别是捕获和冒泡。和许多Web技术一样,在它们成为标准之前,Netscape和微软各自不同地实现了它们。Netscape选择实现了捕获事件流,微软则实现了冒泡事件流。幸运的是,W3C决定组合使用这两种方法,并且大多数新浏览器都遵循这两种事件流方式。
1事件传播——冒泡与捕获
概念:
事件冒泡:事件最开始由最具体的元素接收(文档层次中嵌套最深的那个节点),然后逐级向上传播最不具体的节点(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事件流:将事件分为三个阶段:捕获阶段、目标阶段、冒泡阶段。先调用捕获阶段的处理函数,其次调用目标阶段的处理函数,最后调用冒泡阶段的处理函数。
<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中的事件冒泡、事件捕获和事件执行顺序的更多相关文章
- 事件冒泡与捕获&事件托付
设想这样一种情况 一个div里面有个span元素 ,当鼠标单击span时,这个事件算是谁的? div还是span? 准确的说两个都触发了,这种认可大家都允许,事实就是这种, 第二个问题来了,这个事件 ...
- JavaScript权威设计--事件冒泡,捕获,事件句柄,事件源,事件对象(简要学习笔记十八)
1.事件冒泡与事件捕获 2.事件与事件句柄 3.事件委托:利用事件的冒泡技术.子元素的事件最终会冒泡到父元素直到跟节点.事件监听会分析从子元素冒泡上来的事件. 事件委托的好处: 1.每个函 ...
- JavaScript事件冒泡与捕获
event.preventDefault(); 如果event.cancelable的值为true,可以取消默认事件 event.cancelable; 元素是否可以取消 ...
- 整理之DOM事件阶段、冒泡与捕获、事件委托、ie事件和dom模型事件、鼠标事件
整理之DOM事件阶段 本文主要解决的问题: 事件流 DOM事件流的三个阶段 先理解流的概念 在现今的JavaScript中随处可见.比如说React中的单向数据流,Node中的流,又或是今天本文所讲的 ...
- [JS]笔记12之事件机制--事件冒泡和捕获--事件监听--阻止事件传播
-->事件冒泡和捕获-->事件监听-->阻止事件传播 一.事件冒泡和捕获 1.概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的oncl ...
- js事件机制——事件冒泡和捕获
概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的onclick事件也会被触发.js里称这种事件连续发生的机制为事件冒泡或者事件捕获. IE浏览器:事件从 ...
- JS 事件冒泡、捕获。学习记录
作为一个转行刚到公司的新人,任务不多,这一周任务全部消灭,闲暇的一天也别闲着,悄悄的看起了书.今天写一下JS的事件冒泡.捕获. 也是今天看的内容有点多了,有些消化不了,就随手记录一下.纯属自我理解,如 ...
- DOM事件-冒泡、捕获、传播、委托
事件捕获 以点击事件为例事,同类型事件会由根元素开始触发,向内传播,一直到目标元素.从外到内依次触发:根—目标的祖先素—目标的父元素—目标元素. 事件冒泡 根事件捕获截然相反.发生点击事件时,事件会从 ...
- JavaScript 中的内存和性能、模拟事件(读书笔记思维导图)
由于事件处理程序可以为现代 Web 应用程序提供交互能力,因此许多开发人员会不分青红皂白地向页面中添加大量的处理程序.在 JavaScript 中,添加到页面上的事件处理程序数量将直接关系到页面的整体 ...
- JS 事件冒泡整理 浏览器的事件流
JavaScript与HTML的交互通过事件来实现.而浏览器的事件流是一个非常重要的概念.不去讨论那些古老的浏览器有事件捕获与事件冒泡的争议, 只需要知道在DOM2中规定的事件流包括了三个部分,事件捕 ...
随机推荐
- operator->和operator->*
->和->*都是C++中定义的可重载的运算符,其中:->称为成员选择符(member selection),而->*称为成员指针选择符(pointer-to-member se ...
- 自由缩放属性resize
为了增强用户体验,CSS3增加了很多新的属性,其中resize就是一个重要的属性,它允许用户通过拖动的方式来修改元素的尺寸来改变元素的大小.到目前为止,可以使用overflow属性的任何容器元素. 在 ...
- py2exe使用方法
一.简介 py2exe是一个将python脚本转换成windows上的可独立执行的可执行程序(*.exe)的工具,这样,你就可以不用装python而在windows系统上运行这个可执行程序. py2e ...
- python 在最后一行追加
2.文本文件的写入 import fileinput file = open("D:\\test.txt", encoding="utf-8",mode=&qu ...
- NIO SelectionKey中定义的4种事件
SelectionKey.OP_ACCEPT —— 接收连接继续事件,表示服务器监听到了客户连接,服务器可以接收这个连接了 SelectionKey.OP_CONNECT —— 连接就绪事件,表示客户 ...
- hdu2068RPG的错排
Problem Description 今年暑假杭电ACM集训队第一次组成女生队,其中有一队叫RPG,但做为集训队成员之一的野骆驼竟然不知道RPG三个人具体是谁谁.RPG给他机会让他猜猜,第一次猜:R ...
- HTML5 Web app开发工具Kendo UI Web中如何绑定网格到远程数据
在前面的文章中对于Kendo UI中的Grid控件的一些基础的配置和使用做了一些介绍,本文来看看如何将Kendo UI 中的Grid网格控件绑定到远程数据. 众所周知Grid网格控件是用户界面的一个重 ...
- WCF、MongoDB
http://www.cnblogs.com/quietwalk/archive/2011/08/09/2132573.html http://www.cnblogs.com/huangxinchen ...
- spring @condition 注解
spring @condition注解是用来在不同条件下注入不同实现的 demo如下: package com.foreveross.service.weixin.test.condition; im ...
- 微信H5页面内实现一键关注公众号
H5页面内实现关注公众号的微信JSSDK没有相关接口开放,因此就得动点脑筋来实现该功能了.下面的方法就是通过一种非常蹊跷的方式实现的. 首先,需要在公众号内发表一篇原创文章,注意是原创文章,然后由另一 ...