本系列的介绍中指出,“HTML 元素是构成文档对象模型的节点”。我们已经讨论了元素节点的类型。在本部分中,我们将介绍用于查询这些节点的元素 API。
DOM 和 AOM
DOM 是一个用于访问和操作文档的 API。DOM 是文档中所有节点的树。有些节点可以有子节点,有些则不可以。该树包含元素及其属性和文本节点。

浏览器工具不会提供上述树状可视化图表,但您可以在元素检查器中看到这些节点。

在浏览器开发者工具中可检查的树形表示法是无障碍树。AOM 基于 DOM;同样,无障碍树包含代表所有标记元素、属性和文本节点的对象:

HTML 元素 API
DOM 的中间字母是“object”。就像大多数面向对象编程入门课程中的 person 或 car 对象示例一样,文档树中的每个节点都是一个可使用 JavaScript 操控的对象。
该浏览器提供了许多 API,可提供原生支持的方法、事件以及属性查询和更新。元素节点包含与元素上设置的所有属性相关的信息。您可以使用 HTML 接口来访问有关元素属性的信息。例如,我们可以使用 HTMLImageElement.alt 获取所有图片的 alt 属性:
let allImages = document.querySelectorAll('img');
allImages.forEach((imageInstance) => {
console.log(imageInstance.alt);
});
HTML 接口不仅可让您访问元素的属性,还可让您访问更多信息。我们可以找到只读的 HTMLElement.offsetHeight,以获取网页中相对于布局的每个版块的高度。
let allSections = document.querySelectorAll('section');
allSections.forEach((sectionInstance) => {
console.log(sectionInstance.offsetHeight);
});
如果用户更改设备屏幕方向或以其他方式更改视口的宽度,每个 <section> 的高度都会发生变化,并且 DOM 属性也会随之自动更新。
HTML 接口 API 不仅可用于访问属性值。DOM 可让您深入了解界面的当前状态。HTML API 可以访问所有这些信息。您可以分别通过 HTMLMediaElement.duration、HTMLMediaElement.currentTime 和 HTMLMediaElement.ended 访问视频的长度、当前播放的观看位置,以及视频(或音频)是否已播放完毕。
可用的元素接口
除了一些分区元素外,本系列中到目前为止介绍过的以及尚未介绍的大多数 HTML 元素都具有关联的 DOM 接口。所有元素的基准接口恰当地命名为 Element。HTMLElement 继承自 Element,所有 HTML 元素专用接口都继承自它。某些特定于元素的接口由多个类似元素实现。
接口包括:
HTMLAnchorElement-<a>HTMLAreaElement-<area>HTMLAudioElement-<audio>HTMLBaseElement-<base>HTMLButtonElement-<button>HTMLCanvasElement-<canvas>HTMLDataElement-<data>HTMLDataListElement-<datalist>HTMLDetailsElement-<details>HTMLDialogElement-<dialog>HTMLEmbedElement-<embed>HTMLFieldSetElement-<fieldset>HTMLFormElement-<form>HTMLHtmlElement-<html>HTMLIFrameElement-<iframe>HTMLImageElement-<img>HTMLInputElement-<input>HTMLLabelElement-<label>HTMLLegendElement-<legend>HTMLLIElement-<li>HTMLLinkElement-<link>HTMLMapElement-<map>HTMLMediaElement-<audio>,<video>HTMLMenuElement-<menu>HTMLMetaElement-<meta>HTMLMeterElement-<meter>HTMLModElement-<ins>,<del>HTMLObjectElement-<object>HTMLOListElement-<ol>HTMLOptGroupElement-<optgroup>HTMLOptionElement-<option>HTMLOutputElement-<output>HTMLPictureElement-<picture>HTMLProgressElement-<progress>HTMLQuoteElement-<q>、<blockquote>、<cite>HTMLScriptElement-<script>HTMLSelectElement-<select>HTMLSlotElement-<slot>HTMLSourceElement-<source>HTMLStyleElement-<style>HTMLTableCellElement-<td>,<th>HTMLTableColElement-<col>,<colgroup>HTMLTableElement-<table>HTMLTableRowElement-<tr>HTMLTableSectionElement-<thead>、<tbody>、<tfoot>HTMLTemplateElement-<template>HTMLTextAreaElement-<textarea>HTMLTimeElement-<time>HTMLTitleElement-<title>HTMLTrackElement-<track>HTMLVideoElement-<video>
命名惯例为“HTML”后跟大驼峰式命名的元素或元素分组,再跟“元素”,但元素或元素分组部分没有遵循确切的模式。不必担心,您无需记住这些内容。 只需知道它们的存在即可,以便在需要时查找它们。
如果您有一系列元素,则还可以使用一些集合接口。例如,HTMLCollection.namedItem() 方法会返回集合中 id 或 name 属性与参数匹配的第一个元素;如果没有元素匹配,则返回 null。
除 HTMLElement 外,超过 30 个元素没有关联的 DOM 接口,其中包括 <address>、<article>、<section>、<nav>、<header>、<footer>、<aside> 和 <hgroup>。许多不支持任何非已废弃的非全局属性的元素都有元素专用接口,例如 HTMLPElement(<p> 元素)和 HTMLUnknownElement(<😃> 或任何其他未定义的元素),但这些接口不会在从 HTMLElement 继承的属性和方法之上实现任何其他属性或方法,并且未列在上面。
冗余的 API 方法和属性
如果接口与其继承的接口具有相同的方法或属性名称,则继承的方法或属性会覆盖被继承的方法或属性。换句话说,父级方法和属性会替换子级方法和属性。当我们使用 imageInstance.alt 和 sectionInstance.offsetHeight 分别访问 HTML 元素 API 中的 alt 和 offsetHeight 属性时,代码无法识别正在访问哪个 API。通常,就像这两个示例一样,这不是问题。
不过,在某些情况下,冗余可能会导致问题。例如,HTMLCollection.length 是只读的,而继承接口 HTMLOptionsCollection 具有具有读写权限的长度属性(仅由 <select> 的 options 属性返回)。HTMLOptionsCollection 可用于设置集合大小。
其他接口
还有一些其他接口可用于操控 DOM 节点的分支位置。EventTarget 接口会向我们提供 addEventListener() 和 removeEventListener(),并会被 Node 和 Window 接口继承。反过来,Element、Document 和 DocumentFragment(我们在自定义元素中曾介绍过)接口会继承自 Node,而 HTMLElement 接口会继承自 Element。
node 接口
每种类型的 DOM 节点都由基于 Node 的接口表示,该接口会提供与 DOM 树相关的元素的信息和方法。Node 接口支持查询节点树并向其添加节点。
Douglas Crockford 的著名“遍历 DOM”函数使用了 Node 的 firstChild 和 nextSibling 属性。
const walk_the_DOM = function walk(node, callback) {
callback(node);
node = node.firstChild;
while (node) {
walk(node, callback);
node = node.nextSibling;
}
};
我们在定义自定义元素时使用了 Node 的 appendChild() 和 cloneNode() 方法。Node 接口提供了许多用于查询和操作 DOM 的实用属性和方法。
customElements.define('star-rating',
class extends HTMLElement {
constructor() {
super(); // Always call super first in constructor
const starRating = document.getElementById('star-rating-template').content;
const shadowRoot = this.attachShadow({
mode: 'open'
});
shadowRoot.appendChild(starRating.cloneNode(true));
}
});
attachShadow() 方法是 Element 接口的方法。此外,还有一个 shadowRoot 接口,用于与文档的主 DOM 树分开呈现的 Shadow DOM API。
Document 和 HTMLDocument 接口
Document 接口继承自 Node。它表示在浏览器中加载的网页,无论文档是 HTML、SVG、XML、MathML 还是其他格式。Document 接口还会继承自 HTMLDocument 接口。
document 可让您快速访问节点类型,并能够创建特定元素类型(例如 document.body 和 document.styleSheets)的集合。借助 HTMLDocument,您可以访问与文档相关但未在 HTML 节点中找到的信息,例如 Document.location、Document.lastModified 和 Document.Cookie。
您可以根据通过文档界面显示的功能使用多种 API,包括 Drag and Drop API 和 FullScreen API。两者均继承自 Element。
Window 接口
Window 接口除了 DOM 之外,还包含可用于操控 DOM 的全局可用项。Window 提供了 MDN 的 JavaScript 和 DOM 参考文档中记录的函数、命名空间、对象和构造函数。
Window 接口是包含文档的对象的 API。全局 window 对象是脚本运行的窗口。每个浏览器标签页都包含自己的 Window 对象。Window 接口可以查询标签页的内容以及整个窗口和设备。例如,resizeTo() 方法可用于调整浏览器窗口的大小,devicePixelRatio 属性可用于访问设备显示屏像素。当您访问内容所在的标签页(而非标签页显示的 DOM 树)的相关信息时,该窗口可能是您要查找的界面。
您可以根据通过 Window 接口提供的功能使用多种 API,包括 Web Worker 和 IndexedDB API。
检查您的理解情况
测试您对 HTML API 相关知识的掌握情况。
DOM 中的 O 代表什么?
哪个界面可以帮助您了解内容所在的标签页的相关信息?