整理之DOM事件阶段、冒泡与捕获、事件委托、ie事件和dom模型事件、鼠标事件
整理之DOM事件阶段
本文主要解决的问题:
- 事件流
- DOM事件流的三个阶段
先理解流的概念
在现今的JavaScript中随处可见。比如说React中的单向数据流,Node中的流,又或是今天本文所讲的DOM事件流。都是流的一种生动体现。用术语说流是对输入输出设备的抽象。以程序的角度说,流是具有方向的数据。
事件流分事件冒泡与事件捕获
在浏览器发展的过程中,开发团队遇到了一个问题。那就是页面中的哪一部分拥有特定的事件?
可以想象画在一张纸上的一组同心圆,如果你把手指放在圆心上,那么你的手指指向的其实不是一个圆,而是纸上所有的圆。放到实际页面中就是,你点击一个按钮,事实上你还同时点击了按钮所有的父元素。
开发团队的问题就在于,当点击按钮时,是按钮最外层的父元素先收到事件并执行,还是具体元素先收到事件并执行?所以这儿引入了事件流的概念。
通俗说,事件流所描述的就是从页面中接受事件的顺序。
因为有两种观点,所以事件流也有两种,分别是事件冒泡和事件捕获。现主流是事件冒泡。
事件冒泡
事件冒泡即事件开始时,由最具体的元素接收(也就是事件发生所在的节点),然后逐级传播到较为不具体的节点。
下面写个例子:

1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Event Bubbling</title>
6 </head>
7 <body>
8 <button id="clickMe">Click Me</button>
9 </body>
10 </html>

然后,我们给button和它的父元素,加入点击事件。

1 var button = document.getElementById('clickMe');
2
3 button.onclick = function() {
4 console.log('1. You click Button');
5 };
6 document.body.onclick = function() {
7 console.log('2. You click body');
8 };
9 document.onclick = function() {
10 console.log('3. You click document');
11 };
12 window.onclick = function() {
13 console.log('4. You click window');
14 };

在Chrome浏览器运行:
如果点击了button,那么这个点击事件会按如下的顺序传播
- button
- body
- document
- window
也就是说,click事件首先在<button>元素上发生,然后逐级向上传播。
事件捕获
事件捕获的概念,与事件冒泡正好相反。它认为当某个事件发生时,父元素应该更早接收到事件,具体元素则最后接收到事件。比如说刚才的demo,如果是事件捕获的话,事件发生顺序会是这样的:
- window
- document
- body
- button
事件阶段(Event Phases)
当一个DOM事件触发时,它不是在触发的对象上只触发一次的,而是经历三个阶段。分别为
1:一开始从文档的根节点流向目标对象(捕获阶段)
2:然后在目标对向上被触发(目标阶段)
3:之后再回溯到文档的根节点(冒泡阶段).
1. 事件捕获阶段
事件的第一个阶段是捕获阶段。事件从文档的根节点出发,随着DOM树的结构向事件的目标节点流去。途中经过各个层次的DOM节点,并在各节点上触发捕获事件,直到到达事件的目标节点。捕获阶段的主要任务是建立传播路径,在冒泡阶段,事件会通过这个路径回溯到文档跟节点。当事件发生时,首先发生的是事件捕获,为父元素截获事件提供了机会。
例如,我把上面的Demo中,window点击事件更改为使用事件捕获模式。(addEventListener最后一个参数,为true则代表使用事件捕获模式,false则表示使用事件冒泡模式。不理解的可以去学习一下addEventListener函数的使用)
1 window.addEventListener('click', function() {
2 console.log('4. You click window');
3 }, true);
此时,点击button的效果是这样的。
可以看到,点击事件先被父元素截获了,且该函数只在事件捕获阶段起作用。
处于目标与事件冒泡阶段
事件到了具体元素时,在具体元素上发生,并且被看成冒泡阶段的一部分。
随后,冒泡阶段发生,事件开始冒泡。
阻止事件冒泡
事件冒泡过程,是可以被阻止的。防止事件冒泡而带来不必要的错误和困扰。
这个方法就是:stopPropagation()
我们对button的click事件做一些改造。
1 button.addEventListener('click', function(event) {
2 // event为事件对象
3 console.log('1. You click Button');
4 event.stopPropagation();
5 console.log('Stop Propagation!');
6 }, false);
点击后,效果如下图:
不难看出,事件在到达具体元素后,停止了冒泡。但不影响父元素的事件捕获。
总结
事件流:描述的就是从页面中接受事件的顺序。
分有事件冒泡与事件捕获两种。
DOM事件流的三个阶段:
- 事件捕获阶段
- 处于目标阶段
- 事件冒泡阶段
参考资料:《JavaScript高级程序设计》第三版
一直没有搞懂jquery中的事件是怎么添加事件处理程序的。原来就是用了事件委托,关键就是通过冒泡方式实现在最高层(document)处理事件,通过判断事件target的id,给以不同的handler。当然也可以通过事件捕获来处理,但是因为ie中只有冒泡,所以还是用冒泡兼容性更好一些。
细细总结一下:
1.冒泡与捕获。
冒泡和捕获是两个完全不同的事件流传播方式,当点击页面上某个元素时,不知道用户是对该元素感兴趣还是对该元素的父元素该兴趣?为此提出了两种不同的事件流模型。一种是捕获,由网景提出的,首先是最不具体的元素接收到事件,然后再一级一级传播到最具体的元素。另一种是冒泡,是由ie提出的,它和捕获完全相反,首先是最具体的元素接收到事件,然后一级一级传播到最不具体的元素,一般都是document。
2.事件委托
上面的参考博文写得很清楚了。大概模式就是这样(以onclick为例子,其他事件mouseover mousemove mouseout mousedown mouseup click dbclick keyup keydown)
document.onclick=function(event){
var event=event?event:window.event;
var target=event.target?event.target:event.srcElement;
switch(target.id){
case:'btnid1':
btnid1handler();
break;
case:'btnid2':
btnid2handler();
break;
}
};
3.ie事件和dom(2)事件模型
ie事件模型的事件流只包括事件冒泡,而dom(2)事件模型的事件流包括三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段。ie8以下的版本只支持ie事件模型,ie9及其他浏览器都支持dom事件流。
区别:
(1)添加事件处理程序的不同。dom0级只能在冒泡阶段调用事件处理程序。dom2级事件模型通过addEventListener支持在冒泡和捕获阶段注册事件处理程序。而ie事件模型通过attachEvent在事件冒泡阶段注册事件处理程序。
(2)事件处理程序的event参数和this的作用域不同。addEventListener中的this就指向当前事件元素,event就是当前事件对象。而attachEvent的this指向window,event是全局对象作用域window中的event对象,但是同时也会作为参数直接传递给事件处理程序函数。但是在只支持ie事件模型的浏览器中通过dom0级方法注册的事件处理程序中的event,只能通过全局的window.event进行访问,但无论在哪个浏览器中,通过dom0级注册的事件处理程序中的this也是指向当前事件元素,可以做到很好的跨浏览器兼容。
(3) 移除事件监听。通过dom0级注册的事件处理程序,通过 element.onclick=null;这样的形式来移除注册事件。通过dom2级事件注册的时间处理程序通过removeEventListener来移除事件处理程序,而ie事件模型通过datachEvent来移除。
(4)阻止默认事件模型和阻止事件冒泡的方法。dom2级可以通过preventDefault来阻止事件的默认行为。ie通过returnValue属性为false来阻止事件的默认行为。dom2采用stopPropagation方法来阻止冒泡,而ie通过cancelBubble属性为true来阻止冒泡。
4 鼠标事件
A表示B元素的外部,B表示元素,C表示B的子元素
鼠标事件有以下几种:
mouseover:从A到B时触发,冒泡
mouseenter:从A到B时触发,并且不冒泡,DOM3级出现的事件
mouseleave:从B到A时触发,并且不冒泡,DOM3级出现的事件
mouseout:从B到A,或者从C到B时触发,冒泡
mousemove:B到B时触发
mousedown:按下任意鼠标按钮时触发
mouseup:释放鼠标按钮时触发
click:在同一个元素相继触发mousedown和mouseup才会触发click事件,任意一个被取消,都不会触发click
dbclick:连续两次click才能触发dbclick。
更多技术分享请关注 http://hist.ac.cn/
整理之DOM事件阶段、冒泡与捕获、事件委托、ie事件和dom模型事件、鼠标事件的更多相关文章
- 初始js闭包&事件的冒泡和捕获&EVENT对象
一.初识闭包 function a(){ var n = 0; this.inc = function () { n++; console.log(n); }; } var ...
- react第五单元(事件系统-原生事件-react中的合成事件-详解事件的冒泡和捕获机制)
第五单元(事件系统-原生事件-react中的合成事件-详解事件的冒泡和捕获机制) 课程目标 深入理解和掌握事件的冒泡及捕获机制 理解react中的合成事件的本质 在react组件中合理的使用原生事件 ...
- 从零开始的全栈工程师——js篇2.20(事件对象 冒泡与捕获)
一.复习 面向对象 1)单例模式 2)工厂模式 3)构造函数 ①类js天生自带的类 基类object function array number math boolean date regexp st ...
- JS事件冒泡与捕获
1事件传播——冒泡与捕获 默认情况下,事件使用冒泡事件流,不使用捕获事件流.然而,在Firefox和Safari里,你可以显式的指定使用捕获事件流,方法是在注册事件时传入useCapture参数,将这 ...
- Dom捕捉事件和冒泡事件-原理与demo测试
先参考一下百度百科对冒泡事件流的解释: ----------不喜欢读文字的同学,可以直接看下面demo,传递顺序简单明了! http://baike.baidu.com/link?url=kaeJHT ...
- 手持设备点击响应速度,鼠标事件与touch事件的那些事
前言 现在一直在做移动端的开发,这次将单页应用的网页内嵌入了app,于是老大反映了一个问题:app应用点击响应慢!我开始不以为然,于是拿着网页版的试了试,好像确实有一定延迟,于是开始了研究,最后选择了 ...
- wxpyhon 鼠标事件例子
#encoding:utf-8 import wx import wx.aui class MyFrame(wx.Frame): def __init__(self, *args, **kwargs) ...
- 浅谈Qt事件的路由机制:鼠标事件
请注意,本文是探讨文章而不是教程,是根据实验和分析得出的结果,可能是错的,因此欢迎别人来探讨和纠正. 这几天对于Qt的事件较为好奇,平时并不怎么常用,一般都是用信号,对于事件的处理,一般都是需要响应键 ...
- PyQt5编程:鼠标事件
参考链接:https://www.cnblogs.com/zhuluqing/p/9028816.html 一.每个事件都被封装成相应的类: pyqt中,每个事件类型都被封装成相应的事件类,如鼠标事件 ...
- opencv-python教程学习系列5-处理鼠标事件
前言 opencv-python教程学习系列记录学习python-opencv过程的点滴,本文主要介绍opencv-python处理鼠标事件,坚持学习,共同进步. 系列教程参照OpenCV-Pytho ...
随机推荐
- php 传递赋值和地址赋值 &
更多内容推荐微信公众号,欢迎关注: 1.传递赋值 $a = 1; $b = 2; $a = $b; echo $a,$b; //结果为:5 5 2.地址赋值 $a = 1; $b = 2; $a = ...
- 更改arch的默认终端
实在是厌倦了gnome的资源管理器nautilus和终端gnome-terminal,于是卸载之,然后更换了xfce4的终端,但是出现了一个问题,那就是在资源管理器中使用邮件打开终端的时候打不开了,解 ...
- AndroidManifest.xml权限设置
访问登记属性 android.permission.ACCESS_CHECKIN_PROPERTIES ,读取或写入登记check-in数据库属性表的权限 获取错略位置 android.permi ...
- 如何调整Linux内核启动中的驱动初始化顺序-驱动加载优先级
Linux内核为不同驱动的加载顺序对应不同的优先级,定义了一些宏: include\linux\init.h #define pure_initcall(fn) __define_initcall(& ...
- MySQL -- SQL 语句
一. 数据库(Database)操作 创建数据库 create database 数据库名 create database 数据库名 character set 字符集 查看数据库 查看数据库服务器中 ...
- Python基础:获取平台相关信息
Windows 10家庭中文版,Python 3.6.4, 本文介绍了使用os.platform.sys三个模块获取Python程序的运行平台相关的信息. os模块:提供 各种各样的操作系统接口 os ...
- css-概述和选择器
一:CSS 概述 CSS 指层叠样式表 (Cascading Style Sheets) 样式定义如何显示 HTML 元素 样式通常存储在样式表中 把样式添加到 HTML 4.0 中,是为了解决内容与 ...
- python基础--shutil模块
shutil模块提供了大量的文件的高级操作. 特别针对文件拷贝和删除,主要功能为目录和文件操作以及压缩操作.对单个文件的操作也可参见os模块. 注意 即便是更高级别的文件复制函数(shutil.cop ...
- 安装pywin32模块
1.先下载pywin32对于的版本 下载地址:python for windows extensions 2.选择自己对应的版本,我的是python3.5版本 注意注意注意:此处一定要看清楚自己的py ...
- 网络路径查询traceroute
Traceroute用法 网友:适兕 发布于: 2006.08.24 08:14 (共有条评论) 查看评论 | 我要评论 一.什么是Traceroute? In ...