DOM tree

一个HTML文档的骨架就是标签(tags)。 根据文档对象模型(Document Object Model,也叫DOM),每个HTML的标签都是一个对象。嵌套的标签就是标签里的children,同样标签里的文本也是一个对象。 所有的这些对象都可以用JavaScript来访问,我们可以用它来修改页面。 举例,document.body就是代表body标签的一个对象。下面的代码将会使页面变成红色,3s 后恢复原状

// make the background red
document.body.style.background = "red";
// return back
setTimeout(() => (document.body.style.background = ""), 3000);

该代码使用style.background来改变document.body的背景色,同样我们也有很多其他属性,例如:

  • innerHTML - 节点的html
  • offsetWidth - 节点的宽度(像素)
  • 等等

我们马上就会学会很多操作DOM的方法,但是首先我们需要了解一下它的结构。

一段DOM的例子

让我们以下面这个简单例子为例

<!DOCTYPE html>
<html>
  <head>
    <title>About elk</title>
  </head>
  <body>
    The truth about elk.
  </body>
</html>

DOM用标签的树结构来表示HTML,它大概是这个样子:

我们可以在live-dom-viewer里,实时查看DOM节点

├── HTML
│   ├── HEAD
│   │   ├── #text ↵␣␣
│   │   ├── TITLE
│   │   │   ├── #text About elk
│   │   └── #text ↵
│   ├── #text ↵
│   ├── BODY
│   │   ├── #text ↵␣␣ The truth about elk.↵

每个树节点都是一个对象。 标签是元素节点(或者仅仅是一个元素),然后形成了一个树结构:<html>是根节点,接着是<head>,然后是<body>和它的子节点,等等。 元素的文本形成了文本节点,用#text来标记,一个文本节点只会包含一个字符串,它不会有子节点,总是树的一片叶子。 例如<title>标签的文本是About elk。 需要注意文本节点里的特殊字符:

  • 换行符:↵(在JavaScript里就是\n
  • 空格:␣

空格和换行也是合法的字符,像字符和数字。他们一起组成了文本节点变成了DOM的一部分。所以在例子中,在<title>标签前有几个空格,接着空格变成了一个#text节点(它只包含换行和一些空格符)。 只有两个顶级标签,除了:

  • <head>标签前的换行,空格符因为一些历史原因会被忽略
  • 如果我们把元素放到</body>之外,那么它会自动移动到body标签里,最后,在 HTML 规范里所有的元素都必须在<body>里。所以在</body>外没有也没有空格

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

<!DOCTYPE html>
<html>
  <head>
    <title>About elk</title>
  </head>
  <body>
    The truth about elk.
  </body>
</html>

对应的树节点如下:

├── HTML
│   ├── HEAD
│   │   ├── TITLE
│   │   │   ├── #text About elk
│   ├── BODY
│   │   ├── #text The truth about elk.

自我纠正

当生成DOM的时候,如果浏览器遇到格式错误的HTML,会自动纠正它。 例如,顶级标签总是 <html>,即使它不存在文档里,也会存在DOM中,因为浏览器会创建这个标签,同样也适用于<body>。 假如一个HTML文件只有一个单词hello,浏览器渲染的时候会把它包裹在htmlbody里,也会加一个head标签,最后DOM会是这个样子:

├── HTML
│   ├── HEAD
│   ├── BODY
│   │   ├── #text hello

在生成DOM的时候,浏览器会自动处理文档的错误,比如关闭标签等等 假如有这一个例子:

<p>
  Hello
  <li>Mom</li>
  <li>and</li>
  <li>Dad</li>
</p>

浏览器读取到丢失的标签,会自动补齐并修复好。

├── HTML
│   ├── HEAD
│   ├── BODY
│   │   ├── P
│   │   │    ├── #text Hello
│   │   ├── LI
│   │   │    ├── #text Mom
│   │   ├── LI
│   │   │    ├── #text and
│   │   ├── LI
│   │   │    ├── #text Dad

其他节点类型

在元素节点和文本节点外还有一些其他的节点类型。比如:注释

<!DOCTYPE html>
<html>
  <body>
    The truth about elk.
    <ol>
      <li>An elk is a smart</li>
      <!-- comment here -->
      <li>...and cunning animal!</li>
    </ol>
  </body>
</html>

对应的树结构如下:

├── HTML
│   ├── HEAD
│   │   ├── #text ↵␣␣
│   │   ├── TITLE
│   │   │   ├── #text About elk
│   │   └── #text ↵
│   ├── #text ↵
│   ├── BODY
│   │   ├── #text ↵␣␣ The truth about elk.↵
│   │   ├── OL
│   │   ├── #text ↵␣␣
│   │   │   ├── LI
│   │   │   │   ├── #text An elk is a smart
│   │   │   ├── #text ↵␣␣
│   │   │   ├── #comment comment here
│   │   │   ├── #text ↵␣␣
│   │   │   ├── LI
│   │   │   │   ├── #text ..and cunning animal!
│   │   │   ├── #text ↵␣␣
│   │   ├── #text ↵␣␣

我们可以看到在 2 个文本节点中间有了一个新的树节点类型-注释节点(comment node),用#comment来表示。 我们可能会纳闷,为啥注释也被加到了DOM里?它是无论如何也不会影响到渲染的。但是有一个规则,如果HTML里面有东西,那么它也必须在DOM树里。

HTML里的所有内容,即使是注释,都会变成DOM的一部分

甚至HTML页面开头的<!DOCTYPE...>指令,也是DOM节点。它在DOM树里的<html>标签前面。很少有人知道这个点,我们碰不到这个节点,我们甚至没有绘制到页面里,但是它就是存在的。 表示整个文档的文档对象在形式上也是一个DOM节点。

总共有12 个节点类型,通常的我们只用到其中 4 个:

  1. document-DOM的入口
  2. 元素节点-HTML标签,构建树的模块
  3. 文本节点-用来包裹文本
  4. 注释-我们会放一些关键信息,它不会显示在页面上,但是JavaScript可以读取到它

总结

HTML/XML文档在浏览器内均被表示为DOM树。

  • 标签(tag)成为元素节点,并形成文档结构。
  • 文本(text)成为文本节点。
  • ……等,HTML中的所有东西在DOM中都有它的位置,甚至对注释也是如此。

DOM节点具有允许我们在它们之间移动、修改它们、在页面中移动等的属性和方法。 我们将在下一章深入探讨它们。

results matching ""

    No results matching ""