DOM-дерево и навигация
DOM-дерево
Что такое DOM
DOM — это объектная модель HTML-документа. Браузер парсит HTML и строит дерево объектов:
<!DOCTYPE html>
<html>
<head>
<title>Страница</title>
</head>
<body>
<h1>Заголовок</h1>
<p>Абзац</p>
</body>
</html>
Это дерево выглядит так:
Document
└── html (Element)
├── head (Element)
│ └── title (Element)
│ └── "Страница" (Text)
└── body (Element)
├── h1 (Element)
│ └── "Заголовок" (Text)
└── p (Element)
└── "Абзац" (Text)
Типы узлов
// Основные типы узлов
document.nodeType // 9 — Document
document.body.nodeType // 1 — Element
document.createTextNode('text').nodeType // 3 — Text
document.createComment('...').nodeType // 8 — Comment
// Константы
Node.ELEMENT_NODE // 1
Node.TEXT_NODE // 3
Node.COMMENT_NODE // 8
Node.DOCUMENT_NODE // 9
Traversal — обход дерева
const ul = document.querySelector('ul')
// Родительский узел
ul.parentNode // ближайший родитель (любой узел)
ul.parentElement // ближайший родитель-элемент
// Дочерние узлы
ul.childNodes // NodeList: все дочерние узлы (включая текст)
ul.children // HTMLCollection: только дочерние Elements
ul.firstChild // первый дочерний узел (может быть текстом)
ul.firstElementChild // первый дочерний Element
ul.lastChild
ul.lastElementChild
// Соседние узлы
ul.nextSibling // следующий сосед (любой узел)
ul.nextElementSibling // следующий Element-сосед
ul.previousElementSibling
childNodes включает текстовые узлы (пробелы и переносы строк в HTML). children — только элементы. Чаще всего нужен именно children.HTMLCollection и NodeList (от querySelectorAll) ведут себя по-разному:
const ul = document.querySelector('ul')
// HTMLCollection — ЖИВАЯ (отражает изменения DOM)
const liveItems = ul.children
console.log(liveItems.length) // 3
ul.appendChild(document.createElement('li'))
console.log(liveItems.length) // 4 — автоматически обновилась!
// NodeList от querySelectorAll — СТАТИЧЕСКИЙ снимок
const staticItems = ul.querySelectorAll('li')
console.log(staticItems.length) // 3
ul.appendChild(document.createElement('li'))
console.log(staticItems.length) // 3 — не изменился!
Это важно при итерации: модификация DOM во время обхода HTMLCollection может дать непредсказуемые результаты. Безопаснее конвертировать в массив: Array.from(ul.children).