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

Содержание

О проверке кода. Примеры не запускались в браузере — в отличие от материалов по Node.js с фактическим выводом. Говорим прямо, а не ставим бейдж «проверено».

Найти элемент — половина дела; вторая — создавать и менять содержимое страницы. Разберём, как это делать правильно и, главное, безопасно.

Создание элемента: три шага

// 1. создать в памяти (на странице ещё не видно)
const card = document.createElement('div');

// 2. настроить
card.className = 'card';
card.textContent = 'Привет';
card.setAttribute('data-id', '42');

// 3. вставить в страницу
document.querySelector('#container').append(card);

createElement создаёт элемент в памяти — до вставки его на странице нет. Дальше задают классы, текст, атрибуты и вставляют в родителя. Методы вставки:

  • parent.append(el) — в конец родителя;
  • parent.prepend(el) — в начало;
  • el.before(other) / el.after(other) — рядом с элементом.

Современный append удобнее старого appendChild: принимает несколько узлов и строки сразу.

textContent против innerHTML: вопрос безопасности

Это важнейшее различие в работе с DOM:

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

el.textContent = '<b>Привет</b>';   // покажет буквально: <b>Привет</b>
el.innerHTML = '<b>Привет</b>';     // покажет жирный: Привет
  • textContent вставляет строку как текст — теги не интерпретируются, это безопасно;
  • innerHTML разбирает строку как HTML — создаёт из неё элементы.

innerHTML мощнее, но именно поэтому опасен с недоверенными данными.

Ловушка XSS: почему нельзя innerHTML с данными пользователя

const userInput = '<img src=x onerror="украсть_куки()">';

// ❌ КАТАСТРОФА — код пользователя выполнится
el.innerHTML = userInput;

// ✅ безопасно — вставится как текст, ничего не выполнится
el.textContent = userInput;
textContent против innerHTML

textContent — безопасно

Всегда для данных пользователя

  • Вставляет как ТЕКСТ
  • Теги не выполняются
  • Защищено от XSS
  • Быстрее (не парсит HTML)

innerHTML — осторожно

Только доверенный HTML

  • Разбирает как HTML
  • Данные юзера → XSS-дыра
  • Внедрённый скрипт выполнится
  • Только для своего статичного HTML

XSS (межсайтовый скриптинг) — одна из самых распространённых веб-уязвимостей. Если данные от пользователя (комментарий, имя, поисковый запрос) попадают в innerHTML, злоумышленник может внедрить исполняемый код. Правило железное: любые данные пользователя — только через textContent. innerHTML допустим лишь для вашего собственного статичного HTML, где нет пользовательского ввода.

Эффективная вставка списков

const items = ['Аня', 'Борис', 'Вера'];
const list = document.querySelector('#list');

// ❌ вставка по одному — каждый раз пересчёт страницы
items.forEach(name => {
  const li = document.createElement('li');
  li.textContent = name;
  list.append(li);        // трогает живой DOM на каждой итерации
});

// ✅ собрать всё, вставить разом
const fragment = document.createDocumentFragment();
items.forEach(name => {
  const li = document.createElement('li');
  li.textContent = name;
  fragment.append(li);    // накапливаем в памяти
});
list.append(fragment);    // одна вставка в DOM

Каждая вставка в живой DOM заставляет браузер пересчитывать layout. При вставке сотен элементов по одному это заметно тормозит. DocumentFragment — временный контейнер в памяти: накапливаете в него, потом вставляете одним вызовом. Браузер пересчитывает страницу один раз вместо сотен.

Изменение существующих элементов

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

el.classList.add('active');       // добавить класс
el.classList.remove('hidden');    // убрать
el.classList.toggle('open');      // переключить
el.classList.contains('active');  // проверить

el.setAttribute('data-id', '99'); // задать атрибут
el.style.display = 'none';        // инлайн-стиль (лучше через классы)

Для управления внешним видом предпочитайте classList прямому style: стили описаны в CSS, а JS только переключает классы. Это разделяет ответственность — логика в JS, оформление в CSS — и код чище.

Удаление

const el = document.querySelector('.card');
el.remove();                      // элемент удаляет сам себя

// очистить содержимое контейнера
container.replaceChildren();      // убрать всех детей разом

el.remove() — современный способ удалить элемент. Короче старого parent.removeChild(el) и не требует ссылки на родителя. Чтобы очистить контейнер от всех детей — replaceChildren() без аргументов (безопаснее, чем innerHTML = '').


Смежные темы: поиск элементов — с чего начать; события DOM — реакция на действия; строки — шаблоны для текста. Полный список — в уроках JavaScript.

Частые вопросы

Как создать новый элемент на странице?
document.createElement(‘div’) создаёт элемент в памяти, затем ему задают содержимое и классы, и вставляют в страницу через parent.append(el) или prepend. Пока элемент не вставлен, его на странице не видно.
Чем textContent отличается от innerHTML?
textContent вставляет текст как есть, безопасно. innerHTML разбирает строку как HTML и создаёт из неё элементы. Для пользовательских данных берут textContent — иначе через innerHTML можно внедрить вредоносный скрипт (XSS).
Опасен ли innerHTML?
Да, если в него попадают данные от пользователя. Строка разбирается как HTML, поэтому введённый тег script или обработчик события может выполниться — это XSS-уязвимость. Для текста всегда textContent, innerHTML только для доверенного HTML.
Как эффективно вставить много элементов?
Собрать их в DocumentFragment или массив и вставить одним вызовом append, а не добавлять по одному в цикле. Каждая вставка в живой DOM вызывает пересчёт страницы, поэтому пакетная вставка заметно быстрее.
Как удалить элемент со страницы?
Вызвать el.remove() на самом элементе — он удалит себя из DOM. Старый способ parent.removeChild(el) тоже работает, но remove короче и не требует ссылки на родителя.