1. 事件流阶段
事件流有三个阶段:
捕获阶段
从window开始,寻找触发事件最深层的节点,过程中如果有节点绑定了对应事件,则触发事件目标阶段
找到事件触及的最深节点冒泡阶段
从最深节点按照捕获的路径进行返回,过程中如果有节点绑定了对应事件,则触发事件
现代浏览器默认都会在冒泡阶段触发事件。
通过一个例子来简单的感受一下。
点击后,观察输出可以发现,事件是点击到的最深层次的节点开始向上执行的。
即从 size-100
到 size-200
到 size-300
,这就是冒泡的过程。
如果想让事件在捕获阶段就执行,可以传递 addEventListener
方法第三个参数。
2. addEventListener 的第三个参数
addEventListener 的第三个参数用来决定事件在冒泡阶段触发还是在捕获阶段触发,其为一个布尔值,传递 false
则事件会在冒泡阶段触发,传递 true
则会在捕获阶段触发。
根据默认浏览器事件是在冒泡阶段触发的规则,上述例子会先触发子节点 .ele2
的事件,再触发 .ele1
的事件。
如果想让 .ele1
在捕获阶段就触发事件,则在绑定事件的时候传递第三个参数为 true
即可。
这样 .ele1
的事件就会在捕获阶段触发。
3. 不符合W3C标准的事件流
早期的 IE 和 Netscape Navigator 是不符合标准的。
前者是使用事件冒泡流,后者使用事件捕获流。
前面的章节有提到过 0级DOM事件
,其提供的绑定事件的方式是不能指定事件触发的阶段的,其原因是在那个阶段下,还没有现在制定的 DOM 事件流
。
当时并没有统一的标准,0级DOM事件
也并不是一套官方出台的标准,所有相关内功全部由浏览器厂商决定。
后来 W3C 很好的整合了这两种模型,便有了现在的 DOM 事件流。
4. 冒泡的终点元素
这个问题其实经常会在面试中被问到,通常题目会是这样的:
其实问的是事件从那个节点开始捕获,然后到目标节点,最后又在哪个节点冒泡结束。
大部分面试者会回答 document
,其实根据事件对象的 path
属性就可以得到答案。
path 属性会返回事件冒泡的路径,其最后是到 window
对象才停止的。
其实这点在标准中也有描述。
5. 小结
开发过程中很少会取改变事件触发的阶段。但是事件流的概念依然重要,因为很多时候要阻止事件冒泡。
理解了事件流,可以理解事件委托的原理,事件委托相关的内容可以参阅事件相关的性能优化。