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

Изменение документа #

Мутации DOM — создание, вставка, замена и удаление узлов. JavaScript может собирать интерфейс после загрузки данных: строки плейлиста, карточки метрик, шаги оформления заказа. Современные методы append, prepend, remove и replaceWith короче, чем связка appendChild / removeChild.


createElement и текст #

const li = document.createElement('li')
li.className = 'track-row'
li.dataset.trackId = 'tr-901'

const title = document.createElement('span')
title.className = 'track-row__title'
title.textContent = 'Midnight Loop'

li.append(title)

textContent безопаснее innerHTML, если строка приходит из API и может содержать символы <.


append, prepend, before, after #

const playlist = document.querySelector('.playlist ul')
const skeleton = document.createElement('li')

skeleton.className = 'track-row track-row--skeleton'
skeleton.textContent = 'Загрузка…'

playlist.prepend(skeleton) // в начало
playlist.append(li) // в конец

skeleton.remove() // удалить после ответа сервера

append принимает несколько узлов и строк:

const summary = document.querySelector('.checkout-summary')
summary.append('Итого: ', document.createElement('strong'))

remove и replaceWith #

const staleWidget = document.querySelector('.widget[data-stale]')
staleWidget?.remove()

const oldBadge = document.querySelector('.widget__badge')
const freshBadge = document.createElement('span')
freshBadge.className = 'widget__badge'
freshBadge.textContent = 'обновлено'

oldBadge.replaceWith(freshBadge)

Устаревший вариант через родителя:

parent.removeChild(child) // эквивалент child.remove()

DocumentFragment #

Пакетная вставка без лишних перерисовок:

const metricsHost = document.querySelector('.dashboard-grid')
const fragment = document.createDocumentFragment()

for (const metric of [
  { id: 'visits', label: 'Визиты', value: '12 408' },
  { id: 'cr', label: 'CR', value: '3.8%' },
]) {
  const card = document.createElement('article')
  card.className = 'widget'
  card.dataset.widget = metric.id
  card.innerHTML = `
    <h2>${metric.label}</h2>
    <p class="widget__value">${metric.value}</p>
  `
  fragment.append(card)
}

metricsHost.append(fragment) // один раз в DOM

Для доверенных шаблонов допустим innerHTML; для пользовательских строк — textContent или createElement.


insertAdjacentHTML #

Быстрая вставка HTML-строки относительно элемента:

const cart = document.querySelector('.cart-items')

cart.insertAdjacentHTML(
  'beforeend',
  `<li class="cart-line" data-sku="ms-02">
     <span class="cart-line__name">Мышь</span>
     <span class="cart-line__qty">1</span>
   </li>`
)

Позиции: beforebegin, afterbegin, beforeend, afterend. Не используйте для больших списков в цикле без фрагмента — каждый вызов парсит HTML заново.


cloneNode #

const templateRow = document.querySelector('.track-row--template')
const copy = templateRow.cloneNode(true) // true — с потомками

copy.classList.remove('track-row--template')
copy.hidden = false
copy.dataset.trackId = 'tr-777'

document.querySelector('.playlist ul').append(copy)

Шаблоны в <template> удобнее для повторяющихся блоков — содержимое не отображается, пока не склонировано.


Итог #

  • createElement + textContent — безопасная сборка узлов.
  • append / prepend / remove / replaceWith — основной API вставки и удаления.
  • DocumentFragment снижает число reflow при массовой отрисовке.
  • insertAdjacentHTML — для статичных фрагментов разметки; осторожно с неэкранированными данными.

См. также #

Часто спрашивают

querySelector или getElementById?
getElementById быстрее и проще для одного id; querySelector гибче за счёт CSS-селекторов. Подробнее