事件系统,业务开发中只要需要与用户进行交互,那么事件是必不可少的,dom 中存在很多事件,比如 click
,scroll
,focus
等等。我们将深入事件系统中,以及事件中常用的一些操作比如 preventDefault
和 stopPropagation
。同时了解事件分发,以及 capturing
和 bubbling
。本文将会有大量的例子。
capturing and bubbling
dom 是一个 tree 模型,当事件进行传播的时候会沿着 dom 的结构进行传播。
事件对象被分派到 event target,但是开始分派之前,必须首先确定事件对象的传播路径。下面这张图呈现出了 event flow。
事件传播路径是事件通过的当前事件目标的有序列表。这个传播路径反映了文档的层次树结构。列表中的最后一项是 event target,列表中前面的项称为目标的祖先,紧接在前面的项称为目标的父项。
一旦确定了传播路径,事件对象就会经过一个或多个事件阶段。共有三个事件阶段:capture phase,target phase 和 bubble phase。如果不支持某个阶段,或者事件对象的传播已停止,则该阶段将被跳过。例如,如果将 bubble
属性设置为 false, 则将跳过 bubble 阶段,如果在调度之前调用了 stopPropagation
,则将跳过所有阶段。事件对象将会完成如下三个阶段:
- capture 阶段:事件对象通过目标的祖先从 window 传播到目标的父级。此阶段也称为捕获阶段。
- target 阶段:事件对象到达事件对象的事件目标。此阶段称为目标阶段。如果事件类型表明事件没有冒泡,则事件对象将在此阶段完成后停止。
- bubble 阶段:事件对象以相反的顺序通过目标的祖先传播,从目标的父级开始,到 window 结束。此阶段也称为冒泡阶段。
假设存在这样一个 html 片段
<html><body><div id="A"><div id="B"><div id="C"></div></div></div></body>
</html>
给 C 增加一个监听器,第三个参数为 true 代表开启了捕获。
document.getElementById('C').addEventListener('click',function (e) {console.log('#C was clicked')},true
)
当用户点击 C 的时候,捕获阶段的分发流是
window
=> document
=> html
=> body
=> … => 目标对象的父
target 阶段就是目标对象
冒泡阶段的事件流是
目标对象父
=> … => body
=> html
=> document
=> window
使用一个具体的例子来看看总体效果,