Понимание объектной модели документа (DOM)
DOM — это основа веб-разработки, связывающая содержимое страницы (HTML), её оформление (CSS) и интерактивное поведение (JavaScript).
DOM (объектная модель документа) является краеугольным камнем веб-разработки: она служит мостом между содержимым страницы (HTML), её оформлением (CSS) и интерактивным поведением (JavaScript). В этой статье рассматривается природа DOM, её связь с HTML и CSS, а также то, как браузеры строят её для отображения веб-страницы.
Что такое DOM?
DOM — это программный интерфейс, реализуемый браузерами, который позволяет скриптам читать, изменять и модифицировать содержимое, структуру и стиль сайта динамически. Он представляет веб-страницу в виде дерева объектов, где каждый узел соответствует части документа — элементу, атрибуту, фрагменту текста или комментарию. DOM не является частью спецификаций HTML или JavaScript; он строится браузером в соответствии со спецификацией DOM, стандартизированной WHATWG и консорциумом W3C.
Удобная аналогия: HTML-файл — это рецепт, а DOM — это готовое блюдо, которое браузер реально подаёт. После завершения разбора HTML-текст перестаёт существовать — JavaScript всегда работает только с DOM. Именно поэтому document.body.innerHTML = '...' изменяет страницу, но никогда не перезаписывает исходный .html-файл на диске.
Как HTML отображается в дерево DOM
Рассмотрим небольшой фрагмент разметки:
<body>
<h1>Hello</h1>
<p>A <em>short</em> note.</p>
</body>Браузер превращает его в дерево, где каждый тег становится узлом-элементом, а каждый фрагмент текста — текстовым узлом:
HTMLBodyElement (body)
├── HTMLHeadingElement (h1)
│ └── #text "Hello"
└── HTMLParagraphElement (p)
├── #text "A "
├── HTMLElement (em)
│ └── #text "short"
└── #text " note."Обратите внимание: пробелы и текст между тегами тоже становятся настоящими узлами — частое удивление, когда ожидаешь, что firstChild будет <h1>, а получаешь текстовый узел. Чтобы узнать, как браузер классифицирует каждый вид узла, см. Понимание узлов DOM и Свойства узла: тип, тег и содержимое.
Обзор разделов по JavaScript DOM
Эта глава является точкой входа в полную серию статей о работе с DOM в JavaScript. Каждая тема ниже ведёт на отдельную главу:
- Понимание узлов DOM — фундаментальные строительные блоки DOM и их структура.
- Выбор элементов DOM — методы поиска элементов, включая
getElement*иquerySelector. - Манипуляции с DOM — добавление, удаление и изменение элементов для создания динамических страниц.
- Работа со стилями в DOM — применение и чтение CSS-стилей через JavaScript.
- Обработка событий в DOM — эффективное реагирование на действия пользователя.
- Обход DOM — навигация по дереву для доступа к родительским, дочерним и соседним узлам.
- Техники манипуляции с DOM — DocumentFragments, клонирование узлов и пакетные обновления.
- Работа с формами — чтение полей ввода, валидация и обработка отправки форм.
- Продвинутые техники DOM — сложные манипуляции и оптимизации.
- Библиотеки для работы с DOM — библиотеки вроде jQuery, упрощающие типовые задачи.
- Совместимость DOM с браузерами — обеспечение единообразного поведения манипуляций в разных браузерах.
- Доступность и DOM — лучшие практики для создания доступных страниц.
- Отладка и инструменты — инспектирование и диагностика DOM.
- Оптимизация производительности — стратегии быстрых и плавных обновлений.
- Интерактивные элементы и виджеты — создание привлекательных интерактивных компонентов.
Взаимосвязь HTML, CSS и DOM
HTML, CSS и DOM тесно взаимодействуют, чтобы отобразить веб-страницу:
- HTML обеспечивает базовую структуру страниц, которая затем представляется в виде дерева DOM.
- CSS управляет компоновкой и внешним видом элементов внутри DOM. Браузер разбирает стили в CSSOM (CSS Object Model), который объединяется с DOM для построения дерева рендеринга. При изменении стилей браузер пересчитывает вычисленные стили и обновляет дерево рендеринга, отражая изменения оформления.
- JavaScript использует DOM для взаимодействия с HTML и CSS и их изменения, обеспечивая динамические изменения содержимого и стиля страницы.
Этот процесс симбиотичен: HTML преобразуется в DOM, CSS стилизует DOM, а JavaScript манипулирует DOM — и всё это обновляет то, что видит пользователь на экране.
Как браузер строит DOM
Процесс построения DOM — критически важная часть того, как веб-браузеры интерпретируют HTML и CSS веб-страницы и превращают их в видимое интерактивное отображение. Вот как этот процесс обычно разворачивается:
- Разбор HTML: Браузер разбирает исходный HTML-код веб-страницы. В ходе этого процесса браузер идентифицирует элементы: теги, атрибуты и их текстовое содержимое. Каждый элемент, атрибут и фрагмент текста становится частью дерева DOM в виде узла.
- Построение дерева DOM: По мере разбора HTML браузер строит дерево DOM, где каждый узел представляет object в документе. Эта древовидная структура отражает структуру HTML, но позволяет языкам программирования, таким как JavaScript, взаимодействовать с элементами страницы программно.
- Построение дерева рендеринга: Параллельно с построением дерева DOM браузер строит дерево рендеринга, объединяющее элементы DOM с соответствующими им CSS-стилями. В отличие от дерева DOM, дерево рендеринга не включает невизуальные элементы, такие как теги
<script>или элементы сdisplay: none;. - Компоновка: После построения дерева рендеринга браузер вычисляет компоновку, определяя точное положение и размер каждого object на экране.
- Отрисовка: Финальный этап — отрисовка дерева рендеринга на экране. На этом шаге узлы дерева рендеринга преобразуются в реальные пиксели, что фактически отображает веб-страницу.
Практический пример: построение и стилизация веб-страницы
Вот простой HTML-пример, демонстрирующий взаимодействие HTML, CSS и DOM:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Sample DOM Page</title>
<style>
#container {
border: 2px solid black;
padding: 20px;
margin-top: 20px;
}
h1 {
color: navy;
}
p {
font-size: 16px;
}
</style>
</head>
<body>
<div id="container">
<h1>Welcome to Our Website</h1>
<p>This is a sample paragraph to demonstrate the DOM in action.</p>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const heading = document.querySelector('h1');
heading.style.backgroundColor = 'yellow';
});
</script>
</body>
</html>Пояснение к примеру
- Структура HTML: Этот HTML-документ определяет структуру страницы, включая контейнер
div, содержащий заголовок и абзац. - Стилизация CSS: Встроенные CSS-стили оформляют контейнер, заголовок и абзац, демонстрируя влияние CSS на внешний вид HTML-элементов.
- Взаимодействие JavaScript: Встроенный скрипт ожидает загрузки DOM, а затем изменяет цвет фона заголовка на жёлтый. Это взаимодействие показывает, как JavaScript может манипулировать DOM после того, как он был построен браузером.
Чтение дерева из JavaScript
Необязательно иметь браузер, чтобы рассуждать о DOM как о структуре данных — это просто граф объектов. Фрагмент ниже строит небольшое дерево из обычных object, отражающее форму DOM (дочерние элементы, имена тегов, текст), и обходит его, подсчитывая узлы-элементы — точно так же, как querySelectorAll('*').length делал бы это в браузере:
// A minimal model of a DOM subtree.
const tree = {
tag: 'body',
children: [
{ tag: 'h1', children: [{ text: 'Hello' }] },
{
tag: 'p',
children: [
{ text: 'A ' },
{ tag: 'em', children: [{ text: 'short' }] },
{ text: ' note.' },
],
},
],
};
function countElements(node) {
// A node is an "element" when it has a tag; text nodes only have `text`.
let count = node.tag ? 1 : 0;
for (const child of node.children ?? []) {
count += countElements(child);
}
return count;
}
console.log(countElements(tree)); // 4Дерево содержит четыре узла-элемента (body, h1, p, em); простые строки являются текстовыми узлами и не учитываются. Этот рекурсивный обход — та же идея, что лежит в основе реального обхода DOM; см. Обход DOM для изучения браузерных API (childNodes, firstElementChild, parentNode и других).
Типичные подводные камни
- Текст и пробелы тоже являются узлами.
element.childNodesвключает текстовые узлы для переносов строк и пробелов между тегами. ИспользуйтеchildrenилиfirstElementChild, если нужны только элементы. - Запускайте скрипты после того, как DOM существует. Тег
<script>в<head>выполняется до того, как body разобран, поэтомуdocument.querySelector('h1')вернётnull. ДождитесьDOMContentLoaded, разместите скрипт в конце<body>или добавьте атрибутdefer. innerHTMLне бесплатен. ПрисвоениеinnerHTMLповторно разбирает строку и перестраивает всё это поддерево, уничтожая существующие узлы и их обработчики событий. Для небольших изменений текста предпочитайтеtextContent; для структурных изменений рассмотрите DocumentFragments.- DOM живёт, HTML-источник — нет. Редактирование DOM никогда не изменяет исходный HTML-файл, а «Просмотр исходного кода» показывает файл в том виде, в котором он был доставлен, а не текущий DOM. Для просмотра живого дерева используйте панель Elements в браузере.
Чтобы оптимизировать веб-взаимодействия, ознакомьтесь со свойствами узлов DOM. Понимание различных типов узлов — элементов и текста — повышает вашу способность писать эффективный, точно нацеленный JavaScript для динамического управления веб-контентом.
Заключение
Понимание DOM необходимо каждому веб-разработчику. Он предоставляет средства для динамического доступа к содержимому, структуре и стилю веб-страницы и их обновления. Овладев принципами взаимодействия DOM с HTML и CSS, разработчики могут создавать более эффективные и динамичные веб-приложения. Эти фундаментальные знания критически важны для управления веб-контентом и создания интерактивных и динамических сайтов.