Что такое DOM?

👨‍💻 Frontend Developer 🟠 Может встретиться 🎚️ Средний
#JavaScript #HTML #Browser

Краткий ответ

DOM (Document Object Model) — это объектная модель документа, которая представляет HTML как дерево объектов:

  1. Структура — иерархическое дерево узлов 🌳
  2. Интерфейс — API для работы с элементами 🔧
  3. Динамичность — изменение содержимого в реальном времени ⚡
  4. Кроссплатформенность — единый стандарт для браузеров 🌐
  5. Событийность — обработка пользовательских действий 🖱️
  6. Программируемость — управление через JavaScript 💻
// Основные операции с DOM
document.getElementById('myId');
document.querySelector('.myClass');
element.innerHTML = 'Новый контент';
element.addEventListener('click', handler);

Полный ответ

DOM — это как мост между HTML-разметкой и JavaScript! Браузер превращает статичный HTML в живое дерево объектов, с которыми можно взаимодействовать. 🌉

Структура DOM

Иерархия узлов

DOM представляет документ как дерево:

<!DOCTYPE html>
<html>
  <head>
    <title>Заголовок</title>
  </head>
  <body>
    <h1>Привет</h1>
    <p>Текст параграфа</p>
  </body>
</html>
// Структура в DOM
document
├── html
    ├── head
    │   └── title
    │       └── "Заголовок"
    └── body
        ├── h1
        │   └── "Привет"
        └── p
            └── "Текст параграфа"

Типы узлов

// Основные типы узлов
Node.ELEMENT_NODE = 1;        // <div>, <p>
Node.TEXT_NODE = 3;           // Текстовый контент
Node.COMMENT_NODE = 8;        // <!-- комментарий -->
Node.DOCUMENT_NODE = 9;       // document
 
// Проверка типа
if (node.nodeType === Node.ELEMENT_NODE) {
  console.log('Это элемент');
}

Поиск элементов

Основные методы

// По ID
const element = document.getElementById('myId');
 
// По классу
const elements = document.getElementsByClassName('myClass');
 
// По тегу
const paragraphs = document.getElementsByTagName('p');
 
// CSS селекторы
const first = document.querySelector('.class');
const all = document.querySelectorAll('div > p');

Навигация по DOM

// Родительские элементы
element.parentNode;
element.parentElement;
 
// Дочерние элементы
element.childNodes;        // Все узлы
element.children;          // Только элементы
element.firstChild;
element.lastChild;
 
// Соседние элементы
element.nextSibling;
element.previousSibling;
element.nextElementSibling;

Манипуляции с содержимым

Изменение контента

// Текстовое содержимое
element.textContent = 'Новый текст';
element.innerText = 'Видимый текст';
 
// HTML содержимое
element.innerHTML = '<strong>Жирный текст</strong>';
 
// Атрибуты
element.setAttribute('class', 'newClass');
element.getAttribute('id');
element.removeAttribute('style');

Работа со стилями

// Прямое изменение стилей
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.fontSize = '16px';
 
// CSS классы
element.classList.add('active');
element.classList.remove('hidden');
element.classList.toggle('visible');
element.classList.contains('selected');

Создание и удаление элементов

Создание элементов

// Создание нового элемента
const div = document.createElement('div');
div.textContent = 'Новый блок';
div.className = 'my-class';
 
// Добавление в DOM
document.body.appendChild(div);
parent.insertBefore(div, referenceNode);
parent.insertAdjacentHTML('beforeend', '<p>HTML</p>');

Удаление элементов

// Удаление элемента
element.remove();
parent.removeChild(element);
 
// Замена элемента
parent.replaceChild(newElement, oldElement);
 
// Клонирование
const clone = element.cloneNode(true); // true = глубокое

События DOM

Добавление обработчиков

// Современный способ
element.addEventListener('click', function(event) {
  console.log('Клик!', event.target);
});
 
// Множественные обработчики
element.addEventListener('click', handler1);
element.addEventListener('click', handler2);
 
// Удаление обработчика
element.removeEventListener('click', handler1);

Всплытие и погружение

// Фаза погружения (capture)
element.addEventListener('click', handler, true);
 
// Остановка всплытия
function handler(event) {
  event.stopPropagation();
  event.preventDefault();
}
 
// Делегирование событий
document.addEventListener('click', function(event) {
  if (event.target.matches('.button')) {
    console.log('Кнопка нажата');
  }
});

Производительность DOM

Оптимизация операций

// Плохо: множественные обращения
for (let i = 0; i < 1000; i++) {
  document.body.appendChild(createElement());
}
 
// Хорошо: batch операции
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
  fragment.appendChild(createElement());
}
document.body.appendChild(fragment);

Кеширование элементов

// Плохо: повторные поиски
document.getElementById('myId').style.color = 'red';
document.getElementById('myId').style.fontSize = '16px';
 
// Хорошо: кеширование
const element = document.getElementById('myId');
element.style.color = 'red';
element.style.fontSize = '16px';

Современные API

Intersection Observer

// Отслеживание видимости элементов
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('Элемент виден');
    }
  });
});
 
observer.observe(element);

Mutation Observer

// Отслеживание изменений DOM
const observer = new MutationObserver((mutations) => {
  mutations.forEach(mutation => {
    console.log('DOM изменился:', mutation.type);
  });
});
 
observer.observe(document.body, {
  childList: true,
  subtree: true,
  attributes: true
});

Virtual DOM vs Real DOM

Проблемы Real DOM

// Медленные операции
element.innerHTML = newContent;  // Перерисовка
element.style.color = 'red';     // Reflow/Repaint

Концепция Virtual DOM

// Виртуальное представление
const vdom = {
  type: 'div',
  props: { className: 'container' },
  children: [
    { type: 'h1', children: 'Заголовок' },
    { type: 'p', children: 'Текст' }
  ]
};

Лучшие практики

1. Минимизация DOM операций

// Группировка изменений
element.style.cssText = 'color: red; font-size: 16px;';
 
// Использование классов вместо прямых стилей
element.className = 'active highlighted';

2. Делегирование событий

// Вместо множества обработчиков
document.addEventListener('click', function(event) {
  const target = event.target;
  
  if (target.matches('.button')) {
    handleButton(target);
  } else if (target.matches('.link')) {
    handleLink(target);
  }
});

3. Ленивая загрузка

// Создание элементов по требованию
function createExpensiveElement() {
  if (!this.cachedElement) {
    this.cachedElement = document.createElement('div');
    // Настройка элемента
  }
  return this.cachedElement;
}

Распространённые ошибки

Неправильно:

// Поиск в цикле
for (let i = 0; i < items.length; i++) {
  document.getElementById('list').appendChild(items[i]);
}
 
// Забыли про память
element.addEventListener('click', handler);
// Не удалили обработчик при удалении элемента

Правильно:

// Кеширование и batch операции
const list = document.getElementById('list');
const fragment = document.createDocumentFragment();
 
items.forEach(item => fragment.appendChild(item));
list.appendChild(fragment);
 
// Очистка обработчиков
element.removeEventListener('click', handler);

Заключение

DOM — основа интерактивности веб-страниц:

  • Изучайте структуру и методы работы
  • Оптимизируйте операции для производительности
  • Используйте современные API
  • Применяйте лучшие практики

Понимание DOM — ключ к эффективной веб-разработке! 🚀