原文链接:https://javascript.info/dom-nodes,translate with ❤️ by zhangbao.

HTML 文档的骨干 是标签。

根据文档对象模型(DOM),每个 HTML 标签都是一个对象。嵌套标签被称为封闭标签的“孩子”。

标签里的文本也是对象。

所有这些对象都可以通过 JavaScript 获取。

DOM 树的例子

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>About elks</title>
  5. </head>
  6. <body>
  7. <p>The truth about elks.</p>
  8. </body>
  9. </html>

用 DOM 树表示这段代码是这样的:

  1. HTML
  2. HEAD
  3. #text ↵␣␣
  4. TITLE
  5. #text About elks
  6. #text ↵
  7. #text ↵
  8. BODY
  9. #text ↵␣␣
  10. P
  11. #text The truth about elks.
  12. #text ↵↵

标签称为元素节点(或简称元素)。嵌套标签是所在封闭标签的孩子。结果,我们就得到一个元素树了:<html> 是根元素,<head><body> 是它的孩子等。

元素内的文本成为文本节点,标记为 #text ,文本节点仅包含字符串。它可能没有孩子,作为元素树的叶子节点存在。

比如:<title> 标签包含文本节点 "About elks"

下面给出了在上面文本节点中出现的特殊字符的意思:

  • 换行符:(也就是 \n

  • 空格符:

空格和换行符都属于有效字符。它们组成文本节点,并成为 DOM 树的一部分。比如,前面例子里,<head> 标签里的 <title> 前面有一个换行符和两个空格符组成的文本节点 #text

我们还能看到 <body> 的最后一个子节点的内容是 ↵↵,第一个 是 指 </p> 标签后面的换行符,第二个 是指 </body> 后面的换行符。

但有两种例外情况:

  1. <head> 标签之前的空格和换行符,由于历史原因,会被忽略,

  2. 如果我们在 </body> 之后写了代码,都会被自动移动到 <body> 中,因为 HTML 规范要求所有的内容都必须在 <body> 中。所以,</body> 之后没有空格。

在其他情况下,一切都很简单——如果文档中有空格(就像任何字符一样),那么它们就会成为 DOM 中的文本节点,如果我们删除它们,也就没有了。

下面是不存在空格的,纯文本节点的 HTML 代码例子:

  1. <!DOCTYPE html>
  2. <html><head><title>About elks</title></head><body><p>The truth about elks.</p></body></html>

对应 DOM 树结构如下:

  1. HTML
  2. HEAD
  3. TITLE
  4. #text About elks
  5. BODY
  6. P
  7. #text The truth about elks.

DOM  树 - 图1边缘空格和中间空文本通常会被开发者工具隐藏

展示 DOM 的浏览器工具(很快就会介绍)通常不会显示文本开头/结尾处的空格,也不会显示标签之间(换行)的空文本节点。

因为这些内容都是修饰性的,(几乎)不会影响最终的 HTML 内容展现。

为了保证后面的行文简洁,之后的 DOM 树结构里会忽略这些内容。

自动校正

浏览器生成 DOM 树的时候,对于不正确的 HTML 结构会自动校正。

比如:顶部标签总是 <html>,即使代码里没有写,浏览器生成 DOM 树的时候,也会创建它。然后是 <body>

写个例子:HTML 文件里只有一个 "Hello",浏览器会将其封装进 <html><body> 中。

  1. ▼HTML
  2. ▼HEAD
  3. ▼BODY
  4. #text Hello

在生成 DOM 的时候,浏览器自动处理文档中的错处,在必要时闭合标签等。

这样一个”无效”的文档:

  1. <p>Hello
  2. <li>Mom
  3. <li>and
  4. <li>Dad

在经过浏览器校正之后,DOM 树结构变成如下这样:

  1. HTML
  2. HEAD
  3. BODY
  4. P
  5. #text Hello
  6. LI
  7. #text Mom
  8. LI
  9. #text and
  10. LI
  11. #text Dad

DOM  树 - 图2表格总包有 `` 标签

一个有趣的“特别案例”是表格。根据 DOM 规范,一个表格必须包含 标签,虽然 HTML 官方规范里在使用时常常忽略,不过浏览器总是会在最终的 DOM 渲染树里自动插入 </tbody> 标签。

如下的 HTML 结构:

  1. <table id="table"><tr><td>1</td></tr></table>

渲染出来的 DOM 结构将是:

DOM  树 - 图3

其他节点类型

为“DOM 树的例子”一节中的文档,添加更多标签和注释。

  1. <!DOCTYPE html>
  2. <html>
  3. <body>
  4. <p>The truth about elks.</p>
  5. <ol>
  6. <li>An elk is a smart</li>
  7. <!-- comment -->
  8. <li>...and cunning animal!</li>
  9. </ol>
  10. </body>
  11. </html>
  1. HTML
  2. HEAD
  3. BODY
  4. #text ↵␣␣
  5. P
  6. #text The truth about elks.
  7. #text ↵␣␣
  8. OL
  9. #text ↵␣␣␣␣
  10. LI
  11. #text An elk is a smart
  12. #comment comment
  13. #text ↵␣␣␣␣
  14. LI
  15. #text ...and cunning animal!
  16. #text ↵␣␣
  17. #text ↵↵

我们引入了一个新的节点类型——注释节点,标记为 #comment

我们可能感觉奇怪,为什么 DOM 里还会有注释节点呢,毕竟没有它也不会影响页面最终展示效果的。但就是这样,这是规则:HTML 文档里的任何内容,甚至注释,在对应的 DOM 树中都有一个节点与之对应。

甚至 HTML 开头的文档声明 <!DOCTYPE html> 都是 DOM 树中的一个节点,<html> 紧随其后,我们不打算讲它,所有 DOM 树中也没有画出它,但它确实是存在的。

document 对象代表整个文档,并且它也是一个 DOM 节点。

一共有 12 个节点类型。实践中,我们常接触 4 个:

  1. document:DOM 树的“入口”。

  2. 元素节点:HTML 标签,DOM 树的构建块。

  3. 文本节点:文本。

  4. 注释:有时我们可以将一些提示信息放在那里,它不会显示,但可以用 JavaScript 从 DOM 中读到它。

自己看

这里有一个网址 Live DOM Viewer,是一个查看文档结构的小工具。输入你的 HTML 代码,程序就会立刻输出对应的 DOM 树结构,可以点开感受一下。

在浏览器中检查

另一种查看 DOM 树的方式是使用浏览器提供的开发者工具。实际开发中,我们也最常用到它。

点开 elks.html 页面,打开浏览器开发者工具,切换至 Elements 选项卡,你就能看到如下的视图:

DOM  树 - 图4

你可以看到 DOM 树结构,再点击元素的话,能看到关于该元素的更多信息。

请注意,在此展示的 DOM 结构是简化的。文本节点只作为一个纯文本展示,这里也没有“空白”(仅包含空格)文本节点。这很好,因为多数时间,我们关心的是元素节点。

单击开发者工具左上角 DOM  树 - 图5 按钮后,我们就可以使用鼠标(或其他指针设备)从网页中选择节点并“检查”它(在“元素”选项卡中滚动到它)。在我们处于一个庞大的 HTML 页面中(对应巨大 DOM)并且希望观察其中某个特定元素位置时,非常有用。

另一个查看元素的方式,是在网页中的元素上右键,点击菜单列表中的“检查”选项。

DOM  树 - 图6

工具栏的右侧包含如下的子选项卡:

  • Styles:我们可以看到当前元素应用的所有 CSS 样式,包括浏览器内置样式(灰色背景标识)。几乎所有样式都是可编辑的,比如盒子的 width/height/margin/padding

  • Computed:当前元素的计算属性值,即元素最终应用的样式(包括继承过来的样式)。

  • Event Listeners:当前元素绑定的事件处理程序(会在本教程的下一部分讲解)。

  • ……

最好的学习方式就是点来点去,许多值都是可以直接编辑的。

操作控制台

在我们观察 DOM 节点时,也会碰到要对其进行 JavaScript 操作的需要。像:获取一个节点,并对其进行一些修改。下面举了一个结合使用 Elements 选项卡和控制台的例子。

  • Elements 选项卡中选择第一个 <li>

  • 按下 ESC,会发现控制台在 Elements 选项卡下打开了。

现在我们选中的元素可以通过 $0 在控制台中被访问到。而之前选择的那个元素使用 $1 即可访问,以此类推。

我们可以在这些元素上执行命令。比如:$0.style.background = 'red',就会发现被我们选中的元素背景变红了。

DOM  树 - 图7

这也表示,我们通过一个变量引用了页面中的 DOM 元素。我们还可以用 inspect(node) 去监听到 Elements 选项卡里的特定元素(跟我们手动点击元素的效果类似)。

或者我们可以在控制台直接输出它,“原地”检查,以下面的 document.body 为例:

DOM  树 - 图8

上面介绍这些只是为了方便我们 debug。下一章我们介绍怎么使用 JavaScript 修改 DOM。

浏览器开发者工具在我们开发中会给我们带来很大的帮助:帮助我们查看 DOM,观察程序里哪个地方出了问题。

总结

HTML/XML 文档会被浏览器解析成一个 DOM 树结构。

  • 标签变成了元素节点。

  • 文本变成文本节点。

  • ……任何在 HTML 文档中的内容在 DOM 中都有一个节点与之对应,甚至是注释。

我们可以通过开发者工具观察和手动修改 DOM。关于 Chrome 开发工具有大量的文档,地址在 https://developers.google.com/web/tools/chrome-devtools。最好地学习工具的方式就是点来点去,阅读菜单栏,许多选项一看就能懂。

DOM 节点包含许多属性和方法,允许在它们之做遍历、修改、移动页面内容等操作。我们将在下一章介绍。

(完)