DOM: Document Object Model, дерево элементов
🌳 Что такое DOM и зачем он нужен?
DOM (Document Object Model) — это программное представление HTML-документа в виде дерева объектов. Браузер создаёт его автоматически при загрузке страницы, чтобы JavaScript мог взаимодействовать с элементами.
Без DOM мы не смогли бы: - Изменять контент страницы динамически - Реагировать на действия пользователя - Создавать интерактивные интерфейсы
<!-- Пример простого HTML -->
<div id="app">
<h1>Привет, мир!</h1>
<button>Нажми меня</button>
</div>
В DOM этот фрагмент превратится в иерархическую структуру:
document
└── html
├── head
└── body
└── div#app
├── h1
└── button
Основные типы узлов DOM
DOM состоит из разных типов узлов. Вот самые важные:
| Тип узла | Пример | Описание |
|---|---|---|
| Элемент | <div>, <p> |
HTML-теги |
| Текст | "Привет" |
Текстовое содержимое элементов |
| Комментарий | <!-- комментарий --> |
HTML-комментарии |
| Документ | document |
Корень дерева |
🔍 Интересный факт: пробелы и переносы строк между тегами тоже становятся текстовыми узлами!
🔍 Как исследовать DOM в браузере
- Инструменты разработчика (F12) → Вкладка "Elements"
- Консоль →
documentдля доступа к корню DOM - JavaScript → методы для навигации по дереву
// Получаем элемент по id
const appDiv = document.getElementById('app');
// Получаем все элементы по тегу
const buttons = document.getElementsByTagName('button');
// Современный метод (аналог jQuery)
const h1 = document.querySelector('#app h1');
Навигация по DOM-дереву
У каждого DOM-элемента есть полезные свойства для перемещения:
const div = document.querySelector('div');
// Дочерние элементы
console.log(div.children); // Только элементы
console.log(div.childNodes); // Все узлы (включая текстовые)
// Родительский элемент
console.log(div.parentNode);
// Соседние элементы
console.log(div.previousElementSibling);
console.log(div.nextElementSibling);
💡 Совет:
childrenвозвращает только элементы, аchildNodes— все узлы, включая текстовые и комментарии.
🌱 Создание и изменение элементов
DOM позволяет не только читать, но и изменять структуру страницы:
// Создаём новый элемент
const newParagraph = document.createElement('p');
newParagraph.textContent = 'Новый абзац!';
// Добавляем в DOM
document.body.appendChild(newParagraph);
// Изменяем стиль
newParagraph.style.color = 'blue';
// Добавляем класс
newParagraph.classList.add('highlight');
// Удаляем элемент через 3 секунды
setTimeout(() => {
newParagraph.remove();
}, 3000);
🎯 Практический пример: интерактивный список
Давайте создадим список дел с возможностью добавления и удаления задач:
<div id="todo-app">
<input type="text" id="task-input">
<button id="add-btn">Добавить</button>
<ul id="task-list"></ul>
</div>
const input = document.getElementById('task-input');
const addBtn = document.getElementById('add-btn');
const taskList = document.getElementById('task-list');
addBtn.addEventListener('click', () => {
if (input.value.trim() === '') return;
const li = document.createElement('li');
li.textContent = input.value;
const deleteBtn = document.createElement('button');
deleteBtn.textContent = '❌';
deleteBtn.addEventListener('click', () => li.remove());
li.appendChild(deleteBtn);
taskList.appendChild(li);
input.value = '';
});
🚀 Производительность работы с DOM
Операции с DOM — одни из самых "дорогих" в JavaScript. Вот как их оптимизировать:
- Минимизируйте обращения к DOM — кэшируйте элементы в переменные
- Используйте DocumentFragment для массового добавления элементов
- Избегайте "перекомпоновки" (reflow) при частых изменениях стилей
// Неоптимально (много перекомпоновок)
for (let i = 0; i < 100; i++) {
const div = document.createElement('div');
document.body.appendChild(div);
}
// Оптимально (одна перекомпоновка)
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const div = document.createElement('div');
fragment.appendChild(div);
}
document.body.appendChild(fragment);
🔥 Продвинутые техники
Shadow DOM
Позволяет создавать изолированные DOM-поддеревья (используется в веб-компонентах).
const host = document.getElementById('host');
const shadowRoot = host.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `<style>p { color: red; }</style><p>Только в Shadow DOM!</p>`;
MutationObserver
Следит за изменениями в DOM и выполняет колбэк при их обнаружении.
const observer = new MutationObserver(mutations => {
console.log('DOM изменился!', mutations);
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true
});