灏天阁

前端 DOM 事件流模型

· Yin灏

前端DOM事件流模型.png

相关概念

事件

事件是指在 Web 页面中发生的各种交互行为,例如单击、双击、鼠标移动、键盘按键等。当用户执行这些交互行为时,Web 浏览器会自动触发相应的事件,然后调用相应的事件处理器来处理这些事件。

事件对象

事件对象是指在事件处理器中 JavaScript 对象(Event),它包含了与事件相关的各种信息,例如事件的类型、目标元素、触发时间、鼠标坐标、键盘按键等。在事件处理器中,我们可以通过事件对象来获取这些信息,然后对事件进行处理或响应。

常用的属性有:

  1. target:表示事件的目标对象,即触发事件的对象(事件触发的目标)。
  2. currentTarget:表示事件的当前目标对象,即事件正在处理的对象(事件监听的目标,监听器所在的元素)。
  3. type:表示事件的类型,例如 clickmouseover 等。
  4. detail:自定义事件中,用于在事件对象中传递一些额外的信息。

需要注意的是,detail属性的值必须是一个纯对象,即不能包含函数、循环引用等引用类型的数据。

事件类型

事件类型是指各种事件的分类。在编写事件处理器时,需要明确处理的事件类型,以便在事件触发时调用相应的事件处理器。

常用的一些类型有:

  1. 鼠标事件(MouseEvent): click dbclick mouseover mouseout
  2. 键盘事件(KeyboardEvent): keydown keyup
  3. 表单事件(FormDataEvent): submit reset change input select
  4. 焦点事件(FocusEvent): focus blur
  5. 视窗事件(UIEvent): resize scroll

注:在JavaScript中事件的类是Event,这些事件类型的类MouseEventKeyboardEventFocusEvent等都是其子类。

事件流

事件流是指事件在 Web 页面中传播的方式,即从事件的起点开始,经过各个元素的传播路径,最终到达事件的终点的过程。事件流主要分为两种模式:冒泡模式捕获模式

事件处理器

事件处理器是指在 Web 页面中编写的处理事件的函数,例如 onClickonMouseOver 等。当特定的事件触发时,Web浏览器会调用相应的事件处理器来响应事件。

常用的事件处理方式包括使用 onclick 属性、addEventListener 方法。

示例

<div id="outer">
  <div id="middle">
    <div id="inner">Click Me</div>
  </div>
</div>
const outer = document.getElementById("outer");
const middle = document.getElementById("middle");
const inner = document.getElementById("inner");

outer.addEventListener(
  "click",
  function (event) {
    console.log("capture outer clicked");
  },
  true
);
outer.addEventListener(
  "click",
  function (event) {
    console.log("bubble outer clicked");
  },
  false
);
middle.addEventListener(
  "click",
  function (event) {
    console.log("capture middle clicked");
  },
  true
);
middle.addEventListener(
  "click",
  function (event) {
    console.log("bubble middle clicked");
  },
  false
);
inner.addEventListener(
  "click",
  function (event) {
    console.log("capture inner clicked");
  },
  true
);
inner.addEventListener(
  "click",
  function (event) {
    console.log("bubble inner clicked");
  },
  false
);

打印结果为:

capture outer clicked
capture middle clicked
capture inner clicked
bubble inner clicked
bubble middle clicked
bubble outer clicked

在这个例子中

  1. 事件就是点击了Click Me的行为。
  2. addEventListener是设置事件监听,第一个参数click事件的类型,第二个参数是一个函数,它就是事件处理器,事件处理器的参数是event就是事件对象
  3. 从日志可见,事件是一步一步按照一定顺序执行的,这就是事件流

事件流模型

模型发展史

早期的 IE 浏览器和网景浏览器在事件处理方面存在差异,IE 使用的是事件冒泡模型,而网景使用的是事件捕获模型。这导致了在开发跨浏览器应用时的事件处理问题。 为了解决这个问题,W3C 组织在 DOM Level 2 规范中定义了事件流模型,它将事件捕获和事件冒泡两种模型结合起来,使得所有浏览器都可以支持相同的事件处理方式。

DOM 是什么?

文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展置标语言的标准编程接口。DOM 把整个页面映射为一个多层的节点结构,HTML 或 XML 页面中的每个组成部分都是某种类型的节点,这些节点又包含着不同类型的数据。

W3C DOM 由以下三部分组成:

核心 DOM - 针对任何结构化文档的标准模型 XML DOM - 针对 XML 文档的标准模型 HTML DOM - 针对 HTML 文档的标准模型 通过 DOM 接口,应用程序可以在任何时候访问文档中的任何一部分数据,因此,这种利用 DOM 接口的机制也被称作随机访问机制。

DOM1、DOM2 又是什么?

DOM 标准是由 W3C(World Wide Web Consortium,万维网联盟)制定的一套标准,包括DOM Level 1DOM Level 2DOM Level 3等不同级别的规范。这些规范定义了 DOM 接口的具体实现,包括 DOM 节点、DOM 事件、DOM CSS 样式等相关内容。因此,可以说 DOM 是基于 DOM 标准规范实现的。

DOM1 级主要定义了 HTML 和 XML 文档的底层结构。 在 DOM1 的基础上 DOM2 引入了更多的交互能力,也支持了更高级的 XML 特性。DOM2 将 DOM 分为更多具有联系的模块。DOM2 级在原来 DOM 的基础上又扩充了鼠标、用户界面事件、范围、遍历等细分模块,而且通过对象接口增加了对 CSS 的支持。

在 DOM2 中引入了下列模块,在模块包含了众多新类型和新接口:

  • DOM 视图(DOM Views):定义了跟踪不同文档视图的接口
  • DOM 事件(DOM Events):定义了事件和事件处理的接口
  • DOM 样式(DOM Style):定义了基于 CSS 为元素应用样式的接口
  • DOM 遍历和范围(DOM Traversal and Range):定义了遍历和操作文档树的接口

模型介绍

dom事件流的副本.webp

在 DOM 事件流中,事件分为三个阶段:捕获阶段目标阶段冒泡阶段

  • 捕获阶段:事件从文档根节点开始,向事件发生的目标元素传播。在这个阶段,事件从文档根节点开始向下传播,一直传播到目标元素。
  • 目标阶段:事件已经到达目标元素。
  • 冒泡阶段:事件从目标元素开始,向文档根节点传播。在这个阶段,事件从目标元素开始向上冒泡,一直到达文档根节点。

相关 API

addEventListener

1. addEventListener (type, listener[, useCapture ])
2. addEventListener (type, listener[, options ])

addEventListener有三个参数,第三个参数可以使一个boolean值可以是一个对象。

  1. useCapture 这个参数,如果是 true,表示在捕获阶段调用事件处理程序; 如果是 false,表示在冒泡阶段调用事件处理程序。
  2. opttions 是一个选项对象,包括以下参数:
    • capture: 表示事件是否在捕获阶段进行处理。默认为 false,即在冒泡阶段处理事件。
    • once: 表示事件是否只触发一次。默认为 false
    • passive: 表示事件监听器是否不会调用 preventDefault()。默认为 false。如果不阻止默认行为,使用 {passive: true} 能够有效的增加流畅度。

stopPropagation

有时候,我们需要阻止事件在节点间传播。我们可以使用stopPropagation()方法来停止事件在捕获和冒泡阶段中的传播。

在事件处理函数中使用stopPropagation()方法,可以阻止事件的进一步传播,从而保证事件仅仅在目标元素上执行。

<div id="outer">
  <div id="inner">Click Me</div>
</div>
const outer = document.getElementById("outer");
const inner = document.getElementById("inner");

outer.addEventListener(
  "click",
  function (event) {
    console.log("outer clicked");
  },
  false
);
inner.addEventListener(
  "click",
  function (event) {
    event.stopPropagation();
    console.log("inner clicked");
  },
  false
);

这个方法比较常用,如上例中,父子控件都设置点击事件的监听器,但是点击子控件并不想触发父控件的监听器,这个时候就可以通过stopPropagation方法来阻止事件的继续传播。

preventDefault

preventDefault是一个事件对象的方法,调用该方法可以阻止事件的默认行为。事件的默认行为是指在特定事件发生时,浏览器会默认执行的行为,例如点击一个链接会跳转到对应的页面,提交表单会刷新页面等。 需要注意的是,只有在事件的 cancelable 属性为 true 时,调用 preventDefault方法才会生效。

<a href="https://www.example.com" id="link"> 跳转链接 </a>
const link = document.getElementById("link");
link.addEventListener("click", function (event) {
  event.preventDefault(); // 取消默认跳转行为
  console.log("点击链接,但是不跳转到链接页面");
});

- Book Lists -