今天因为要用原生js实现轮播效果,所以温故了下DOM事件,说句实话,现在无论什么框架,都离不开DOM操作,毕竟这是我们展示的最基本元素,就像人的细胞。
源自曾经对于DOM事件流原理的“知其然而,不知其所以而然”——只知道click mouseover等实用。基于真正意义上的前端来说是:“理论与实践并行”。
当然,DOM事件涵盖的内容较为庞杂,今天主要分享下DOM事件流。
流
借用小北哥哥一句话:流是具有方向的数据。
事件流之事件冒泡与事件捕获
在浏览器发展的过程中,开发团队经常遇到了一个问题。那就是页面中的哪一部分拥有特定的事件?
可以想象画在一张纸上的一组同心圆,如果你把手指放在圆心上,那么你的手指指向的其实不是一个圆,而是纸上所有的圆。放到实际页面中就是,你点击一个按钮,事实上你还同时点击了按钮所有的父元素。
开发团队的问题就在于,当点击按钮时,是按钮最外层的父元素先收到事件并执行,还是具体元素先收到事件并执行?所以这儿引入了事件流的概念。
事件流所描述的就是从页面中接受事件的顺序。
因为有两种观点,所以事件流也有两种,分别是事件冒泡和事件捕获。现行的主流是事件冒泡。
事件冒泡
事件冒泡即事件开始时,由最具体的元素接收(也就是事件发生所在的节点),然后逐级传播到较为不具体的节点。举个栗子,就很容易明白了。
然后,我们给每个div绑定点击事件。
效果如图所示:
初始图:
点击div.No3之后
在代码所示的页面中,如果点击了class为No3的div时,那么这个点击事件会按如下的顺序传播(Chrome浏览器):
- div.No3
- div.No2
- div.No1
也就是说,click事件首先在
事件捕获
事件捕获的概念,与事件冒泡正好相反。它认为当某个事件发生时,父元素应该更早接收到事件,具体元素则最后接收到事件。比如说刚才的demo,如果是事件捕获的话,事件发生顺序会是这样的:
- div.No3
- div.No2
- div.No1
当然,由于时代更迭,事件冒泡方式更胜一筹。所以放心的使用事件冒泡,有特殊需要再使用事件捕获即可。
DOM事件流
DOM事件流包括三个阶段:
- 事件捕获阶段
- 处于目标阶段
- 事件冒泡阶段
如图所示(图片源于网络,若侵权请告知):
事件捕获阶段
也就是说,当事件发生时,首先发生的是事件捕获,为父元素截获事件提供了机会。
例如,我把上面的Demo中,div.No1点击事件更改为使用事件捕获模式。(addEventListener最后一个参数, 为true则代表使用事件捕获模式 ,false则表示使用事件冒泡模式。不理解的可以去学习一下addEventListener函数的使用)
此时,点击div.No3的效果是这样的。
可以看到,点击事件先被父元素截获了,且该函数只在事件捕获阶段起作用。
处于目标与事件冒泡阶段
事件到了具体元素时,在具体元素上发生,并且被看成冒泡阶段的一部分。随后,冒泡阶段发生,事件开始冒泡。
阻止事件冒泡
事件冒泡过程,是可以被阻止的。防止事件冒泡而带来不必要的错误和困扰。
这个方法就是: stopPropagation()
我们对 div 的click事件做一些改造。
点击div.No2后,效果如下图:
不难看出,事件在到达具体元素后,停止了冒泡。但不影响父元素的事件捕获。
简而言之,事件流:描述的就是从页面中接受事件的顺序。分有事件冒泡与事件捕获两种。DOM事件流的三个阶段:
- 事件捕获阶段
- 处于目标阶段
- 事件冒泡阶段