При работе с 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; // => trueparagraph instanceof HTMLElement; // => true
Если говорить простыми словами, элемент это подтип узла так же как кошка подтип животного.
3. Свойства DOM: узлы и элементы
Помимо различения узлов и элементов нужно ещё различать свойства DOM, которые содержат исключительно узлы или исключительно элементы.
Следующие свойства могут содержать либо узел (
Node
),
либо коллекцию узлов (NodeList
):
node.parentNode; // Node или nullnode.firstChild; // Node или nullnode.lastChild; // Node или nullnode.childNodes; // NodeList
А вот следующие свойства могут содержать либо элементы (
HTMLElement
), либо коллекции элементов
(HTMLCollection
):
node.parentElement; // HTMLElement или nullnode.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?