Создание и изменение элементов 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 — безопасно
Всегда для данных пользователя
- Вставляет как ТЕКСТ
- Теги не выполняются
- Защищено от 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.