DOM事件

为了使DOM元素具有交互能力,例如,对用户点击这一动作做出响应,浏览器为DOM元素提供了事件机制。addEventListener可以为元素绑定一个事件监听器:

// 假设 myButton 是一个按钮
myButton.addEventListener('click', greet, false);
function greet(event) {
// 打印并查看event对象
// 打印arguments,以防忽略了其他参数
console.log('greet: ' + arguments);
alert('Hello world');
}

DOM事件模型

想象以下场景:

<div id="div1">
<div id="div2">
<div id="div3">
文字
</div>
</div>
</div>

当点击div3时,其父元素也会触发被点击这一事件,也就是说,点击div3div1div2bodyhtmldocument也被点击了,均会触发点击事件。

如果div1div2div3这三个元素均添加了click事件监听器,那么哪个回调函数会先执行呢?

早期IE的观点是,应该先调用div3的函数,然后调用div2的函数,以此类推。也就是事件从里向外传播(propagation)。这个过程形象地被称为事件冒泡

Netscape则认为,事件是由外向里传播,以上面的代码为例,事件会先传播到最外层元素div1,然后再传播到div2。如果div1div2均对点击事件进行了监听,那么先执行的会是div1的回调函数。这个过程被称为事件捕获

为了兼容这两种事件流模型,2002年,W3C发布DOM2级事件模型,它规定了事件流包含三个阶段:事件捕获阶段目标阶段事件冒泡阶段。首先按事件捕获的顺序看有没有函数监听,然后按事件冒泡的顺序看有没有函数监听,如果有监听函数就调用,没有就跳过。开发者可以自己选择将监听函数放到捕获阶段还是冒泡阶段。

event flow

event flow

div.addEventListener('click', fn, bool)

如果bool不传或者为falsy值,就让fn走冒泡,即当浏览器在冒泡阶段发现div上有fn监听函数,就会调用fn,调用顺序按事件冒泡模型中的事件传播顺序来。如果booltrue,就在捕获阶段调用fn

事件委托

事件委托是事件流的一个典型应用。考虑以下场景:

<div id="parent">
<button />
<button />
<button />
<button />
</div>

现在想要给div里的所有按钮都添加监听事件,如果分别给每个button添加监听器,不仅代码量多,每个监听器都会占用内存,比较消耗资源。解决办法是,我们可以为父元素div添加一个监听器,这样子元素button被点击的时候事件也会触发。这就是事件委托

事件委托的另一个应用是监听目前不存在,之后可能会动态添加的元素。可以监听这种动态元素的父元素,等点击的时候再判断是不是想要的元素。

Author: kpt

Permalink: http://kpt.ink/2021/08/15/DOM%E4%BA%8B%E4%BB%B6/

文章默认使用 CC BY-NC-SA 4.0 协议进行许可,使用时请注意遵守协议。