文档对象模型 (DOM) 是将 HTML 或 XML 文档视为树结构的接口,其中每个节点都是文档的一个对象。DOM 还提供了一组方法来查询树、改变结构、样式。
DOM 还使用术语 element : 与节点非常相似。那么,DOM 节点和元素有什么区别呢?
# 1.DOM Node 节点
理解节点和元素之间区别的关键是理解节点是什么。
从更高的角度来看,DOM 文档由节点的层次结构组成。每个节点可以有一个父节点和 / 或子节点。
我们看一下下面的 HTML 文档:
<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
</head>
<body>
<!-- Page Body -->
<h2>My Page</h2>
<p id="content">Thank you for visiting my web page!</p>
</body>
</html>
<html> 是文档树中的一个节点。它有 2 个子节点:<head > 和 < body > 节点。
<body> 也是一个具有 3 个子节点的节点:评论 <!-- Page Body -->、标题 < h2 > 和段落 < p>。<body > 节点的父节点是 < html > 节点。
HTML 文档中的标签代表一个节点,有趣的是常规文本也是一个节点。段落节点 <p> 有 1 个子节点:文本节点 "Thank you for visiting my web page!"。
# 1.2 节点类型
如何区分这些不同类型的节点?答案在于 DOM Node 接口,尤其是 Node.nodeType 属性。
Node.nodeType 可以具有以下表示节点类型的值之一:
- Node.ELEMENT_NODE
- Node.ATTRIBUTE_NODE
- Node.TEXT_NODE
- Node.CDATA_SECTION_NODE
- Node.PROCESSING_INSTRUCTION_NODE
- Node.COMMENT_NODE
- Node.DOCUMENT_NODE
- Node.DOCUMENT_TYPE_NODE
- Node.DOCUMENT_FRAGMENT_NODE
- Node.NOTATION_NODE
常量有意义地指示节点类型:例如 Node.ELEMENT_NODE 表示元素节点、Node.TEXT_NODE 表示文本节点、Node.DOCUMENT_NODE 文档节点等。
例如,让我们选择段落节点,并查看其 nodeType 属性:
const paragraph = document.querySelector('p');
paragraph.nodeType === Node.ELEMENT_NODE; // => true
正如预期 paragraph.nodeType 的那样,有值 Node.ELEMENT_NODE,表明该段落是一个元素。
该段落还包含一个文本节点:
const paragraph = document.querySelector('p');
const firstChild = paragraph.childNodes[0];
firstChild.nodeType === Node.TEXT_NODE; // => true
有一个节点类型表示整个节点的文档树 - Node.DOCUMENT_NODE:
document.nodeType === Node.DOCUMENT_NODE; // => true
# 2.DOM Element 元素
了解 DOM 节点是什么之后,现在就是区分 DOM 节点和元素的时候了。
如果你理解了节点术语,那么答案就很明显了:元素是特定类型的节点 —— 元素 (Node.ELEMENT_NODE)。以及文档、评论、文本等类型。
简单来说,元素是使用 HTML 文档中的标记编写的节点。<html>, <head>, <title>, <body>, <h2>,<p > 都是元素,因为它们是由标签表示的。
文档类型、注释、文本节点不是元素,因为它们不是用标签编写的:
<!DOCTYPE html>
<html>
<body>
<!-- Page Body -->
<p>Thank you for visiting my web page!</p>
</body>
</html>
Node 是节点 HTMLElement 的构造函数,是 JavaScript DOM 中元素的构造函数。一个段落,是一个节点,并且还一个元素,既是的一个实例 Node 和 HTMLElement:
const paragraph = document.querySelector('p');
paragraph instanceof Node; // => true
paragraph instanceof HTMLElement; // => true
简单地说,元素是节点的子类型,就像猫是动物的子类型一样。
# 3.DOM 属性:节点和元素
除了区分节点和元素之外,您还需要区分仅包含节点或仅包含元素的 DOM 属性。
以下 Node 类型的属性计算为一个节点或节点集合 (NodeList):
node.parentNode; // Node or null
node.firstChild; // Node or null
node.lastChild; // Node or null
node.childNodes; // NodeList
但是,以下属性是元素或元素集合 (HTMLCollection):
node.parentElement; // HTMLElement or null
node.children; // HTMLCollection
既然两者都 node.childNodes 返回 node.children 一个子列表,为什么这两个属性都有呢?好问题!
考虑以下包含一些文本的段落元素:
<p>
<b>Thank you</b> for visiting my web page!
</p>
打开 demo,然后查看 parapgraph 节点的 childNodes 和属性:children
const paragraph = document.querySelector('p');
paragraph.childNodes; // NodeList: [HTMLElement, Text]
paragraph.children; // HTMLCollection: [HTMLElement]
paragraph.childNodes 集合包含 2 个节点:
粗体元素 <b>Thank you</b>,以及文本节点 for visiting my web page!。
但是,paragraph.children 集合仅包含一项:粗体元素 <b>Thank you</b>。
因为 paragraph.children 只包含元素,所以这里没有包含文本节点,因为它的类型是文本 (Node.TEXT_NODE),而不是元素 ( Node.ELEMENT_NODE)。
同时拥有 node.childNodes 并 node.children 让您选择要访问的子节点的集合:所有子节点或只有子节点是元素。
# 4. 总结
DOM 文档是节点的分层集合。每个节点可以有一个父节点和 / 或子节点。
如果您了解节点是什么,就很容易理解 DOM 节点和元素之间的区别。
节点有类型,元素类型就是其中之一。该元素由 HTML 文档中的标记表示。
测验:什么类型的节点永远没有父节点?