DOM дерево

DOM (Document Object Model) — древовидное представление HTML-документа в виде объектов, доступных для манипуляции через JavaScript.

Зачем нужно

DOM — мост между HTML и JavaScript. Через DOM можно читать содержимое страницы, менять его, добавлять элементы, реагировать на действия пользователя.

Где используется

  • Динамическое изменение страницы
  • Обработка форм и ввода
  • Анимации и визуальные эффекты
  • SPA-фреймворки (React, Vue работают с виртуальным DOM)

Предпосылки

Введение в JavaScript, Объекты

Структура DOM

<!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)

Типы узлов (nodeType)

const el = document.querySelector('h1');

// Основные типы
Node.ELEMENT_NODE;    // 1 — HTML-элемент
Node.TEXT_NODE;       // 3 — текстовый узел
Node.COMMENT_NODE;    // 8 — комментарий
Node.DOCUMENT_NODE;   // 9 — document

console.log(el.nodeType);  // 1
console.log(el.nodeName);  // "H1"
console.log(el.tagName);   // "H1" (только для элементов)

// Текстовый узел
const textNode = el.firstChild;
console.log(textNode.nodeType); // 3
console.log(textNode.nodeValue); // "Заголовок"

document — корень DOM

// Ключевые свойства document
document.documentElement; // <html>
document.head;            // <head>
document.body;            // <body>
document.title;           // заголовок страницы
document.URL;             // текущий URL
document.domain;          // домен
document.readyState;      // "loading" | "interactive" | "complete"

// Коллекции
document.forms;           // все <form>
document.images;          // все <img>
document.links;           // все <a> с href
document.scripts;         // все <script>

Свойства узлов

const div = document.querySelector('div');

// Содержимое
div.innerHTML;     // HTML-содержимое (строка)
div.outerHTML;     // Включая сам элемент
div.textContent;   // Только текст (без тегов)
div.innerText;     // Видимый текст (учитывает CSS display)

// Атрибуты
div.id;                  // значение id
div.className;           // строка классов
div.classList;           // DOMTokenList (add, remove, toggle, contains)
div.getAttribute('data-id');     // любой атрибут
div.setAttribute('data-id', '5');
div.removeAttribute('data-id');
div.hasAttribute('data-id');

// dataset — data-* атрибуты
// <div data-user-id="42" data-role="admin">
div.dataset.userId;  // "42"
div.dataset.role;    // "admin"

// Стили
div.style.color = 'red';
div.style.backgroundColor = 'blue'; // camelCase!
div.style.cssText = 'color: red; background: blue'; // строка
getComputedStyle(div).fontSize; // реальное значение из CSS

Частые ошибки

1. innerHTML vs textContent

const div = document.querySelector('div');

// innerHTML парсит HTML — уязвимость XSS!
div.innerHTML = userInput; // Опасно! Пользователь может вставить <script>

// textContent — безопасно, экранирует HTML
div.textContent = userInput; // Безопасно

2. Скрипт до загрузки DOM

// В <head> без defer — элементы ещё не существуют
const el = document.querySelector('#app'); // null!

// Решения:
// 1. defer атрибут: <script defer src="app.js">
// 2. Скрипт перед </body>
// 3. DOMContentLoaded
document.addEventListener('DOMContentLoaded', () => {
  const el = document.querySelector('#app'); // OK
});

Практика

  1. Выведи в консоль nodeType и nodeName для 5 разных узлов
  2. Измени textContent и innerHTML элемента и сравни результат
  3. Прочитай и установи data-атрибуты через dataset

Связанные темы

Ресурсы