DOM: traversal, create, manipulate
DOM API — низкоуровневый интерфейс браузера к живому дереву документа; знание разницы между innerHTML, textContent и insertAdjacentHTML разделяет джунов от сеньоров и постоянно всплывает в вопросах о XSS и производительности рендеринга.
// Traversal: современный vs legacy APIconst nav = document.querySelector('nav.main'); // CSS-селекторconst items = nav.querySelectorAll(':scope > li'); // :scope — только прямые детиconst first = nav.firstElementChild; // пропускает TextNodeconst par = first.closest('.layout'); // поднимаемся вверх до совпадения
// Итерация без Array.from (NodeList iterable в ES2015+)for (const li of items) li.classList.toggle('active');
// parentNode vs parentElement:// у document.documentElement parentNode = document, parentElement = null// children vs childNodes: children — только Element, childNodes — все узлы (Text, Comment)// Создание и вставка узлов с минимальным числом reflowconst frag = document.createDocumentFragment(); // один reflow вместо Nconst data = ['Alice', 'Bob', 'Carol'];data.forEach(name => { const li = document.createElement('li'); li.textContent = name; // безопасно, не парсит HTML frag.appendChild(li);});document.getElementById('list').appendChild(frag);
// insertAdjacentHTML: 4 позиции — не заменяет существующий контентel.insertAdjacentHTML('beforeend', '<span class="badge">new</span>');el.insertAdjacentHTML('afterbegin', '<span class="icon">★</span>');// 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend'
// cloneNode(true) — глубокая копия со всеми потомками и атрибутамиconst clone = document.querySelector('.card').cloneNode(true);clone.removeAttribute('id'); // id должен быть уникальнымdocument.querySelector('.grid').appendChild(clone);// dataset, classList, атрибуты: правильные APIconst btn = document.querySelector('[data-id]');console.log(btn.dataset.id); // 'data-id' → dataset.id (camelCase)btn.dataset.loading = 'true'; // устанавливает data-loadingbtn.dataset.userId = '42'; // → data-user-id="42"
btn.classList.add('active', 'visible'); // variadicbtn.classList.replace('visible', 'hidden');btn.classList.toggle('open', isOpen); // force-флаг: true=add, false=remove
// setAttribute vs DOM-свойствоinput.setAttribute('disabled', ''); // атрибут (строка)input.disabled = true; // свойство DOM (boolean)// getAttribute('disabled') → '' даже если disabled установлен через свойство
// innerHTML vs outerHTML vs textContentel.textContent = rawStr; // автоэкранирует HTML — безопасноel.innerHTML = trustedHTML; // парсит — XSS если userInput!console.log(el.outerHTML); // сериализует сам элемент + содержимоеИтог: DOM API предоставляет полный набор методов для обхода, создания и мутации дерева; правильный выбор метода вставки критичен для безопасности (XSS) и производительности (reflow).