DOM — селекторы и манипуляции

Document Object Model: поиск элементов, создание, вставка, изменение. Фундамент UI в браузере.

Что это

document — корень DOM-дерева страницы. Все методы поиска и создания узлов сидят на нём. Знать DOM нужно даже если работаешь с React/Vue/Angular — под фреймворком всё равно лежит DOM, и иногда приходится спускаться к нему (refs, custom directives, third-party libs).

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

// По ID — самый быстрый, возвращает Element | null
const header = document.getElementById('header');

// По селектору — мощнее jQuery
const first = document.querySelector('div.header > nav .menu a');
const all = document.querySelectorAll('.card[data-active]'); // NodeList

// По имени тега/класса — живые HTMLCollection (обновляются при изменениях DOM!)
const divs = document.getElementsByTagName('div');
const cards = document.getElementsByClassName('card');

// Удобные алиасы
window.$ = document.querySelector.bind(document);
window.$$ = (sel) => [...document.querySelectorAll(sel)];

Создание и вставка

// Создать элемент
const el = document.createElement('div');
el.className = 'card';
el.textContent = 'Hello'; // безопасно от XSS
el.innerHTML = '<b>HTML</b>'; // только если доверяешь источнику

// Атрибуты
el.setAttribute('data-id', '42');
el.dataset.userId = '42'; // → data-user-id

// Стили
el.style.backgroundColor = 'coral';
el.classList.add('active');
el.classList.toggle('hidden');

// Вставка (современный API)
parent.append(el);          // в конец
parent.prepend(el);         // в начало
sibling.before(el);         // перед
sibling.after(el);          // после
sibling.replaceWith(el);    // заменить

// Старый API
parent.appendChild(el);
parent.insertBefore(el, before);

// Удаление
el.remove();

// Создание поддерева
const div = Object.assign(document.createElement('div'), {
  className: 'card',
  innerHTML: '<h2>Title</h2><p>Body</p>',
});

NodeList vs HTMLCollection

NodeList HTMLCollection
Возвращается из querySelectorAll getElementsBy*
Живая? Чаще нет (статичная) Да (обновляется!)
forEach Есть Нет
Конвертация [...nodes] [...coll]

Подводные камни

  • getElementsByClassName возвращает живую коллекцию — coll[i] может стать другим после изменений DOM. Внутри цикла особенно опасно
  • innerHTML — XSS-риск для user input. Используй textContent или sanitize
  • querySelector тяжелее getElementById (~10x), для горячих путей лучше первый
  • Изменение DOM в цикле триггерит layout thrashing — батчи через DocumentFragment или requestAnimationFrame
  • el.style читает только inline-стили, не computed — для computed getComputedStyle(el)

Используется в bootcamp

  • Везде — практически любое DOM-приложение начинается с document.querySelector
  • Особо: AsyncRace — создание машинок, Podcast Player — рендер списка эпизодов

Ссылки

🎓 Источники

  • 🎓 JavaScript в браузере: Web API (часть 1) · TimurShemsedinov · 2019-10-10
    • DOM — основа UI, под любым фреймворком всё равно DOM.
    • getElementsByClassName возвращает живую коллекцию, querySelector — статичный NodeList.
    • querySelector мощнее, чем jQuery-селекторы — принимает любой CSS-путь.

См. также