- 文档/教程
- 前端
【免费下载链接】en.javascript.info
Modern JavaScript Tutorial
DOM(Document Object Model,文档对象模型)是浏览器对 HTML 文档的内存表示,也是 JavaScript 操作页面的基础。本文围绕《现代 JavaScript 教程》(Modern JavaScript Tutorial)的 DOM 树章节 展开,系统讲解 HTML 标签、文本、注释如何在浏览器中组织成一棵可编程的对象树,并给出节点类型、浏览器自动纠错规则以及开发者工具实操方法,帮助你在进入 DOM 遍历与操作之前建立完整的结构认知。
HTML 的骨架:每个标签都是一个对象
一个 HTML 文档的"骨干"是标签(tags)。按照 DOM 的约定,每个 HTML 标签都是一个对象,被嵌套的标签是外层标签的"孩子"(children),标签内部的文本同样也是对象。所有这些对象都可以通过 JavaScript 访问,并用来修改页面。
例如,document.body就是表示<body>标签的对象。下面的代码会把页面背景变成红色,并在 3 秒后恢复原样:
document.body.style.background = 'red'; // 把背景设为红色 setTimeout(() => document.body.style.background = '', 3000); // 3 秒后恢复这里使用的是style.background属性,但节点对象上还有大量其他属性和方法,例如:
innerHTML—— 节点的 HTML 内容;offsetWidth—— 节点宽度(像素);- ……以及更多。
在后续章节中我们会学习更多 DOM 操作方式,但首先需要理解 DOM 的结构本身。仓库中的下一章 Walking the DOM(遍历 DOM) 就建立在本文的结构基础之上,从document这个"入口点"开始访问任意节点。
一个 DOM 实例:从文档到对象树
先看一份最简单的文档:
<!DOCTYPE HTML> <html> <head> <title>About elk</title> </head> <body> The truth about elk. </body> </html>浏览器会把这段 HTML 表示成由标签构成的树形结构:
<html>位于树根;<head>和<body>是它的孩子;- 依次向下,
<title>是<head>的孩子,文本"About elk"是<title>的孩子。
标签是"元素节点"(element nodes),它们构成了树的主干。标签内部的文本构成"文本节点"(text nodes),在图上标记为#text。文本节点只包含一个字符串,它不能有子节点,永远是树的叶子节点。例如<title>标签内的文本就是"About elk"。
需要特别注意的是文本节点中的特殊字符:
- 换行符:
↵(在 JavaScript 中写作\n); - 空格:
␣。
空格和换行是完全合法的字符,和字母、数字一样。它们会形成文本节点并成为 DOM 的一部分。所以在上面的例子中,<head>标签里<title>之前的空格和换行也构成了一个#text节点(内容只有换行和若干空格)。
不过有两个顶层的例外:
- 出于历史原因,
<head>之前的空格和换行会被忽略; - 如果我们在
</body>之后放任何内容,浏览器会把它自动移到body内部末尾——因为 HTML 规范要求所有内容都必须位于<body>之内,所以</body>之后不可能存在空格。
其他情况则很直接:文档中的空格(如同任何字符一样)会变成 DOM 中的文本节点;如果把它们删掉,DOM 里也就不会有它们。例如下面这份紧凑的 HTML 就没有任何仅含空格的文本节点:
<!DOCTYPE HTML> <html><head><title>About elk</title></head><body>The truth about elk.</body></html>:::smart 提示:开发者工具通常会隐藏行首行尾空格和纯空白的文本节点 浏览器自带的 DOM 工具(后面的章节会介绍)通常不会显示文本首尾的空格,以及标签之间由换行形成的空文本节点——这样做是为了节省屏幕空间。本文后续的 DOM 示意图中,在不影响理解时也会省略这些空白节点。这些空格一般不影响页面显示效果。 :::
自动纠错:浏览器会修补残缺的 HTML
浏览器在构建 DOM 时,如果遇到格式不规范的 HTML,会自动进行修正。
例如,顶层标签永远都是<html>:即使文档里根本没有<html>,DOM 中也会存在它,因为浏览器会自行创建;<body>同理。举例来说,如果 HTML 文件只有孤零零的一个单词"Hello",浏览器会把它包进<html>和<body>,并补上必需的<head>,最终 DOM 结构为:html→head(无子节点)+body→#text("Hello")。
在生成 DOM 的过程中,浏览器还会自动处理文档中的各类错误、补齐闭合标签等等。例如下面这段所有标签都未闭合的文档:
<p>Hello <li>Mom <li>and <li>Dad浏览器读取标签后会补全缺失部分,生成一个完全正常的 DOM:<p>中的文本"Hello",以及三个<li>中分别包含"Mom"、"and"、"Dad"。
表格总是有<tbody>
一个有趣的特殊情况是表格。按 DOM 规范,表格必须有<tbody>标签,但 HTML 文本中可以省略它,这时浏览器会在 DOM 中自动创建<tbody>。比如对于下面的 HTML:
<table id="table"><tr><td>1</td></tr></table>生成的 DOM 结构是:TABLE→TBODY→TR→TD→#text("1")。也就是说,<tbody>是凭空"冒出来"的。我们在处理表格时应当记住这一点,以免产生意外。
其他节点类型:注释、DOCTYPE 与 document
除了元素节点和文本节点,DOM 中还存在其他类型的节点。例如注释(comments):
<!DOCTYPE HTML> <html> <body> The truth about elk. <ol> <li>An elk is a smart</li> <!-- comment --> <li>...and cunning animal!</li> </ol> </body> </html>对应的 DOM 树中,在两个文本节点之间出现了一种新的节点类型——注释节点,标记为#comment。你可能会问:注释不会影响页面的视觉呈现,为什么也要放进 DOM?规则就是:只要出现在 HTML 里,就必须出现在 DOM 树中。
HTML 中的一切,包括注释,都会成为 DOM 的一部分。
甚至文档最开头的<!DOCTYPE...>指令本身也是一个 DOM 节点,它位于 DOM 树中<html>的正前方——这一点很少有人知道。我们一般不会去触碰它,示意图里也常常不画它,但它确实存在。代表整个文档的document对象,形式上也是一个 DOM 节点。
根据 WHATWG DOM 规范,节点一共有 12 种类型,但在实践中我们通常只用到其中 4 种:
document—— 进入 DOM 的"入口点";- 元素节点(element nodes)—— HTML 标签,构建树的积木;
- 文本节点(text nodes)—— 包含文本内容;
- 注释(comments)—— 有时可以把信息写在这里,页面不会显示,但 JavaScript 可以从 DOM 中读取。
亲手查看:Live DOM Viewer 与浏览器开发者工具
要实时查看 DOM 结构,可以试试 Live DOM Viewer:输入文档内容,它会立刻以 DOM 的形式展示出来。
另一种(也是日常开发中最常用的)探索 DOM 的方式,是使用浏览器开发者工具。具体做法是:打开本仓库中的示例页面 elk.html,按 F12(或等效方式)开启浏览器开发者工具,切换到Elements(元素)面板。该示例页面内容如下:
<!DOCTYPE HTML> <html> <body> The truth about elk. <ol> <li>An elk is a smart</li> <!-- comment --> <li>...and cunning animal!</li> </ol> </body> </html>此时 Elements 面板应显示类似下面的 DOM 视图:可以看到 DOM 节点、可以点击元素、查看它们的细节。仓库中的 elk.svg 正是该示例在 Elements 面板中的实际呈现截图。
请注意,开发者工具中的 DOM 结构是简化过的:文本节点只显示为文本,纯空白的文本节点完全不会出现。这没有问题,因为大多数时候我们关心的都是元素节点。
点击 Elements 面板左上角的"选择元素"按钮(仓库中的样式资源 toolbarButtonGlyphs.svg 即用于绘制此类工具图标,相关样式定义可查看 head.html),就可以用鼠标(或其他指针设备)在网页上点选节点,并在 Elements 面板中定位("检查")它。当页面很大、对应的 DOM 也很庞大时,这个功能尤其好用。
另一种更快的办法是:在网页上右键,选择上下文菜单中的"检查(Inspect)",如仓库中的 inspect.svg 所示。
在开发者工具右侧还有若干子面板:
- Styles(样式)—— 逐条查看当前元素应用到的 CSS 规则,包括浏览器内置规则(灰色显示),几乎所有内容都可以就地编辑,包括下方盒模型区域中元素的尺寸/外边距/内边距;
- Computed(计算样式)—— 按属性查看元素实际生效的 CSS,每个属性都能看到是哪条规则赋予它的(包括 CSS 继承等);
- Event Listeners(事件监听器)—— 查看绑定到 DOM 元素上的事件监听器(教程的后续部分会讲到);
- ……等等。
学习这些面板最好的方式就是动手点一点。大部分值都可以就地编辑。
与控制台交互:$0、$1 与 inspect()
在处理 DOM 时,我们常常还想对它应用 JavaScript:拿到一个节点,运行代码去修改它、查看结果。下面是一些在 Elements 面板和 Console(控制台)之间来回穿梭的技巧。
起步步骤:
- 在 Elements 面板中选中第一个
<li>; - 按
key:Esc—— 会在 Elements 面板正下方打开控制台。
此时,最后选中的元素在控制台中可用$0引用,之前选中的是$1,依此类推。我们可以对它们运行命令,例如$0.style.background = 'red'会把选中的列表项变成红色(效果如仓库中的 domconsole0.svg 所示)。这就是"从 Elements 拿节点到 Console 用"的路径。
反向路径同样存在:如果有一个变量引用了某个 DOM 节点,可以在控制台中执行inspect(node),让它显示在 Elements 面板中。也可以直接在控制台输出 DOM 节点并就地展开探索,比如下面的document.body(见仓库中的 domconsole1.svg)。
这些当然都是调试用途。从下一章开始,我们会用 JavaScript 来访问和修改 DOM。浏览器开发者工具在开发中是极好的助手:可以探索 DOM、尝试各种操作、观察哪里出了问题。
总结
浏览器把 HTML/XML 文档表示为一棵DOM 树:
- 标签变成元素节点,构成树的结构;
- 文本变成文本节点;
- ……诸如此类,HTML 中的一切在 DOM 中都有位置,连注释也不例外。
我们可以用开发者工具检查 DOM,并手动修改它。这里覆盖了最基础、最常用也最重要的操作。关于 Chrome 开发者工具还有大量文档可供深入学习;学习这些工具最好的方式就是到处点一点、读一读菜单——大多数选项的用途一目了然。等你对整体有了概念之后,再查阅文档补齐其余细节即可。
DOM 节点拥有大量属性和方法,允许我们在它们之间穿梭、修改它们、在页面中移动,等等。这些内容将在接下来的章节中逐一展开,你可以直接从下一章 Walking the DOM 开始,学习如何借助document、documentElement、document.body等入口在节点之间导航。
- 文档/教程
- 前端
【免费下载链接】en.javascript.info
Modern JavaScript Tutorial
相关推荐
JavaScript教程:深入理解DOM树结构
JavaScript教程:深入理解DOM树结构 你是否曾经好奇浏览器是如何将HTML代码转换为可视化的网页?或者为什么JavaScript能够动态修改页面内容?
文档教程前端JavaScript教程:深入理解DOM树结构
JavaScript教程:深入理解DOM树结构 什么是DOM树? DOM(文档对象模型)是HTML文档的编程接口,它将HTML文档表示为一个由节点和对象组成的树
文档/教程前端DataScript入门指南:如何在浏览器中构建不可变数据库
DataScript入门指南:如何在浏览器中构建不可变数据库 DataScript是一个轻量级的不可变内存数据库和Datalog查询引擎,专为Clojure、C
数据库后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考