DOM2级事件中addEventListener的执行机制,多个addEventListener同时添加时的执行先后规律:

W3C的DOM事件触发分为三个阶段:
①、事件捕获阶段,即由最顶层元素(一般是从window元素开始,有的浏览器是从document开始,至于其中的差别我稍后会更新)开始,逐次进入dom内部,最后到达目标元素,依次执行绑定在其上的事件
②、处于目标阶段,检测机制到达目标元素,按事件注册顺序执行绑定在目标元素上的事件。
③、事件冒泡阶段,从目标元素出发,向外层元素冒泡,最后到达顶层(window或document),依次执行绑定再其上的事件。

在addEventListener中,利用第三个参数控制其是从哪个阶段开始,“true”是从捕获阶段开始,而“false”则是跳过捕获阶段,从冒泡阶段开始。 看一个简单的例子:

 <script type="text/javascript">
window.onload=function(){
var outer = document.getElementById("outer");
var inner = document.getElementById('inner'); outer.addEventListener("click", function(){
alert("1");
}
, true); inner.addEventListener("click", function(){
alert("2");
}
, true); outer.addEventListener("click",
function(){
alert("3");
}
,false)
}
</script> <body>
<div id="outer">
<div id="inner"></div>
</div>
</body>

  在这个例子里,如果我们点击内层元素inner,那么处于捕获阶段的1最先弹出,接下来是目标元素2弹出,最后是处于冒泡阶段的3弹出,即:1,2,3. 即使在代码里变换三个绑定事件的顺序,只要点击的是inner,这个执行顺序就不会变。

那么问题来了,如果点击的是外层outer的话呢?

要明白这个问题,我们必须明确一点:目标事件在哪一层,事件流就在哪一层回流,即使在outer事件下还有许多子孙节点,事件流都不会在outer之后往内流,此时,inner上的事件不会被触发,因此在这段代码中,只会弹出1和3。

那么这两个数字哪个先弹呢?由于此时事件处于第二阶段,即“处于目标阶段”,弹出顺序取决的也不再是捕获或冒泡,而是谁在代码中先注册,因此,在这段代码中,弹出的是:1→3.

综上所述,事件在DOM中的执行顺序为:外层捕获事件→内层捕获事件→先注册的目标事件→后注册的目标事件→内层冒泡事件→外层冒泡事件

让我们再看个例子来加深这个概念:

 <script type="text/javascript">
window.onload=function(){
var outer = document.getElementById("outer");
var inner = document.getElementById('inner');
var oBox=document.getElementById('box'); oBox.addEventListener("click",function(){
alert('1');
},true)
oBox.addEventListener("click",function(){
alert('4');
},false) outer.addEventListener("click", function(){
alert("2");
}, true); inner.addEventListener("click",function(){
alert('3.2')
},false) inner.addEventListener("click", function(){
alert("3.1");
}, true); }
</script> <body>
<div id="box">
<div id="outer">
<div id="inner"></div>
</div>
</div>
</body>

在这段代码里,box上的捕获事件最先执行,然后是outer上的捕获事件,然后是inner上先注册的事件,然后是inner上后注册的事件,最后是box上的冒泡事件 弹出顺序为:1→2→3.2→3.1→4

补充一点,在ie8-中,由于addEventLister不起作用,我们使用attachEvent方法来绑定事件,此时在第二阶段,也就是处于目标阶段,如果目标元素上绑定了两个事件,那么其执行顺序和addEventLister相反:谁后注册谁先执行.

接下来我们将问题再升级,如果dom0级事件和dom2级事件同时存在,那执行顺序会是怎样呢?

看下面的事例代码:

 <!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>dom2</title>
<style>
#box{
width:500px;
height:500px;
background-color: red;
} #outer{
width:200px;
height:200px;
background-color: green;
}
#inner{
width:100px;
height:100px;
background-color: yellow;
}
</style>
</head>
<body>
<div id="box">
<div id="outer">
<div id="inner"></div>
</div>
</div>
</body> <script type="text/javascript">
window.onload = function () { var outer = document.getElementById("outer");
var inner = document.getElementById('inner');
var oBox = document.getElementById('box'); oBox.addEventListener("click", function () {
alert('oBox-Dom2冒泡');
}, false); oBox.addEventListener("click", function () {
alert('oBox-Dom2捕获');
}, true); outer.addEventListener("click", function () {
alert("outer-Dom2冒泡");
}, false); outer.addEventListener("click", function () {
alert("outer-Dom2捕获");
}, true); outer.onclick=function(){
alert("outer-dom0 click! ");
} inner.addEventListener("click", function () {
alert('inner-Dom2冒泡');
}, false); inner.addEventListener("click", function () {
alert("inner-Dom2捕获");
}, true);
}
</script>

此案例中,我将outer的div在捕获阶段和冒泡阶段都绑定了点击事件,同时还在绑定了dom0级的点击事件处理函数,这时如果我们点击inner,我们会发现,事件的执行顺序是这样的  oBox-Dom2捕获--> outer-Dom2捕获 --> inner-Dom2冒泡 -->  inner-Dom2捕获 --> outer-Dom2冒泡 --> outer-dom0 click! --> oBox-Dom2冒泡 由此我们可以得出一个结论:当绑定dom0级事件元素不是目标元素时,那么绑定dom0级事件的处理是在冒泡阶段处理并按事件注册的先后顺序执行(W3C先注册的先执行) ,如果绑定dom0级事件的元素是目标元素时,则不论是捕获阶段绑定的处理函数还是冒泡阶段绑定的处理函数以及dom0级事件处理函数,他们的执行顺序都是按照注册的顺序执行(W3C先注册的先执行) 。

关于DOM2级事件的事件捕获和事件冒泡的更多相关文章

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

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

  2. javascript -- 事件捕获,事件冒泡

    使用js的时候,当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,单击子元素时,父元素的onclick事件也会被触发.js里称这种事件连续发生的机制为事件冒泡或者事件捕获. 为什么会 ...

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

    谈起JavaScript的 事件,事件冒泡.事件捕获.阻止默认事件这三个话题,无论是面试还是在平时的工作中,都很难避免. DOM事件标准定义了两种事件流,这两种事件流有着显著的不同并且可能对你的应用有 ...

  4. JS事件捕获和事件冒泡

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; line-height: 19.0px; font: 14.0px "Helvetica Neue" ...

  5. WPF事件(一)内置路由事件

    原文:WPF事件(一)内置路由事件 Windows是消息驱动的操作系统,运行其上的程序也遵照这个机制运行,随着面向对象开发平台日趋成熟,微软把消息机制封装成了更容易让人理解的事件模型,一个事件包含3个 ...

  6. JavaScript 之默认行为 DOM2级,事件委托机制

    1. 事件默认行为及阻止方式    1.1 浏览器的默认行为       JavaScript事件本身所具有的属性,例如a标签的跳转,Submit按钮的提交,右键菜单,文本框的输入等.    1.2 ...

  7. DOM1级问题与DOM2级事件

    前几天有小伙伴问过我一个问题,为什么有DOM 0级事件以及DOM2级事件,但是却没有DOM1级事件呢?那我们今天就来说一说DOM的级别问题. 同时推荐伙伴们可以看看尚学堂有关JavaScript BO ...

  8. DOM2级事件处理程序

    DOM2级时间定义了两个方法:addEventListener() 和removeEventListener() 他们都接受3个参数:1)要处理的事件名   2)作为事件处理程序的函数 3)一个布尔值 ...

  9. 2015-03-12——简析DOM2级事件

    DOM2级事件 事件的几种类型:对象事件,鼠标事件,键盘事件,表单事件,W3CDOM事件,以及针对浏览器的事件. 对象事件:window对象,也是javascript对象.load  适用于windo ...

随机推荐

  1. javascript学习之this

    转自:https://www.cnblogs.com/pssp/p/5216085.html 例子1:  function a(){ var user = "追梦子"; conso ...

  2. vue 项目要使用的库

    1.Stylus是一个CSS预处理器. npm install stylus --save-dev npm install stylus-loader --save-dev 使用 <style ...

  3. 2-2 vue环境搭建以及vue-cli使用

    一.vue多页面应用文件引用 1.官网拷贝: <script src="https://cdn.jsdelivr.net/npm/vue"></script> ...

  4. 不同.NET Framework版本下ASP.NET FormsAuthentication的兼容性

    假设站点A加密使用.NET Framework 2.0,站点B解密使用.NET Framework 4.0,除了保持MachineKey相同外还需要进行如下设置: 1.Web.config的<a ...

  5. JS的压缩、混淆、加密

    参考: 博客园:js压缩.混淆和加密 知乎:前端如何给 JavaScript 加密(不是混淆)?  (阿里聚安全有回答问题) 站长工具  (在线JS压缩加密工具) Obfuscator (在家JS压缩 ...

  6. Altium Designer 输出 gerber 光绘文件的详细说明

    Altium Designer 输出 gerber 光绘文件的详细说明 PCB画好后,我们需要输出光绘文件交给制版厂家.由此,输出光绘文件的重要性就显出来了. 先复习一下介绍各层的定义吧,哈哈 (1) ...

  7. java的前缀自增自减和后缀自增自减

    2.前缀自增自减法(++a,--a): 先进行自增或者自减运算,再进行表达式运算. 3.后缀自增自减法(a++,a--): 先进行表达式运算,再进行自增或者自减运算 实例: 实例 public cla ...

  8. 万事开头难 && 实践出真知

    实践出真知,真是千古不变的真理. 前几天在顺手做一个万年历项目,实现了用TFT屏显示实时时间,日期,温度,和按键设置时间,能在特定时间显示特定的话语在显示屏上面.其实这个项目现在想想还是挺简单的.我的 ...

  9. opengl学习笔记(三):经过纹理贴图的棋盘

    opengl纹理贴图的步骤: 1:创建纹理对象,并为它指定一个纹理 2:确定纹理如何应用到每个像素上 3:启用纹理贴图功能 4:绘制场景,提供纹理坐标和几何图形坐标 注意:纹理坐标必须在RGBA模式下 ...

  10. SCSI共享磁盘

    服务器端: [root@scsi ~]# fdisk -l Disk /dev/sda: 32.2 GB, 32212254720 bytes 255 heads, 63 sectors/track, ...