Объектная модель документа (Document Object Model, DOM) — это интерфейс, который рассматривает HTML- или XML-документы в виде древовидных структур, каждый узел которых является объектом документа. DOM, кроме того, предоставляет набор методов для выполнения запросов к дереву документа, для изменения его структуры и для выполнения с ним некоторых других действий.
При работе с DOM, кроме того, используется термин «элемент». Элементы очень похожи на узлы, но, всё же, это — не одно и то же. В чём же разница?
1. Узел DOM
Ключ к пониманию различия между узлом и элементом заключается в знании о том, что собой представляет узел.
Если рассматривать ситуацию в общих чертах, то оказывается, что DOM-документ включает в себя иерархию узлов. У каждого узла может быть родитель и (или) потомок.
Посмотрим на следующий HTML-документ:
<!DOCTYPE html>
<html>
<head>
<title>My Page</title>
</head>
<body>
<!-- Page Body -->
<h2><font color="#3AC1EF">My Page</font></h2>
<p id="content">Thank you for visiting my web page!</p>
</body>
</html>
В документ входит следующая иерархия узлов:
DOM-представление документа
<html>
— это узел в дереве документа. У него есть два дочерних узла — <head>
и <body>
.
У <body>
есть три дочерних узла — комментарий <!-- Page Body -->
, заголовок <h2><font color="#3AC1EF">
и абзац <p>
. Родительским элементом узла <body>
является узел <html>
.
Теги в HTML-документе представляют узлы. Интересно то, что обычный текст — это тоже узел. Узел-абзац <p>
имеет потомка — текстовый узел Thank you for visiting my web page!
.
▍Типы узлов
Как различать узлы разных типов? Ответ кроется в интерфейсе DOM, который носит имя Node. В частности — речь идёт о свойстве 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
После того, как мы разобрались с тем, что такое узел DOM, пришло время поговорить том, чем различаются узлы и элементы DOM.
Если вы как следует вникли в сущность термина «узел», то вам уже всё должно быть понятно. Элемент — это узел особого типа — Node.ELEMENT_NODE
. Это — такой же тип узла, как и другие, представляющие весь документ, комментарии, тексты и прочие узлы DOM.
Если говорить простыми словами, то элемент — это узел, который объявлен с использованием тега в HTML-документе. <html>
, <head>
, <title>
, <body>
, <h2><font color="#3AC1EF">
, <p>
— это всё элементы, так как они представлены тегами.
А вот сам документ, комментарий, текст — это не элементы, так как они не представлены соответствующими тегами:
<!DOCTYPE html>
<html>
<body>
<!-- Page Body -->
<p>
Thank you for visiting my web page!
</p>
</body>
</html>
В DOM-API JavaScript конструктор узла — это Node
, а HTMLElement
— это конструктор элемента. Абзац, хотя это и узел DOM, является ещё и элементом, соответствующий объект является и экземпляром Node
, и экземпляром HTMLElement
:
const paragraph = document.querySelector('p');
paragraph instanceof Node; // => true
paragraph instanceof HTMLElement; // => true
Если говорить простыми словами, элемент — это подтип узла — так же как кошка — подтип животного.
3. Свойства DOM: узлы и элементы
Помимо различения узлов и элементов нужно ещё различать свойства DOM, которые содержат исключительно узлы или исключительно элементы.
Следующие свойства могут содержать либо узел (Node
), либо коллекцию узлов (NodeList
):
node.parentNode; // Node или null
node.firstChild; // Node или null
node.lastChild; // Node или null
node.childNodes; // NodeList
А вот следующие свойства могут содержать либо элементы (HTMLElement
), либо коллекции элементов (HTMLCollection
):
node.parentElement; // HTMLElement или null
node.children; // HTMLCollection
Так как и свойство node.childNodes
, и свойство node.children
возвращает коллекцию сущностей-потомков, возникает вопрос о том, почему существуют оба этих свойства. На самом деле это — хороший вопрос!
Рассмотрим следующий элемент-абзац, содержащий какой-то текст:
<p>
<b>Thank you</b> for visiting my web page!
</p>
Откройте этот демонстрационный пример и посмотрите на свойства childNodes
и children
узла-абзаца:
const paragraph = document.querySelector('p');
paragraph.childNodes; // NodeList: [HTMLElement, Text]
paragraph.children; // HTMLCollection: [HTMLElement]
Коллекция paragraph.childNodes
содержит 2 узла: текст, оформленный полужирным шрифтом с помощью тега <b>
(<b>Thank you</b>
), и текстовый узел (for visiting my web page!
).
Но в коллекции paragraph.children
имеется лишь 1 элемент, представленный тегом <b>
(<b>Thank you</b>
).
Так как свойство paragraph.children
содержит только элементы, текстовый узел в него не включён. Произошло это из-за того, что с точки зрения системы это — текст (Node.TEXT_NODE
), а не элемент (Node.ELEMENT_NODE
).
То, что у нас есть и node.childNodes
, и node.children
, позволяет нам выбирать именно ту коллекцию элементов-потомков некоего узла DOM, с которой нужно работать. Это может быть либо коллекция, содержащая все узлы-потомки, либо только те узлы-потомки, которые являются элементами.
4. Итоги
Документ DOM — это иерархическая коллекция узлов. У каждого узла могут быть родители и (или) потомки.
Отличие между узлами и элементами DOM становится очевидным в том случае, если есть понимание того, что такое узел.
У узлов имеется свойство, указывающее на их тип. Один из этих типов соответствует элементам DOM. Элементы представлены тегами в HTML-документе.
Сталкивались ли вы со сложностями, касающимися различения узлов и элементов DOM?
Автор: ru_vds