Маніпуляція DOM
JavaScript маніпуляція DOM — скульптор вирізає форму з мармурового блоку
У минулому уроці ми навчилися знаходити елементи на сторінці та змінювати їхній текст, стилі та атрибути. Але що, якщо потрібно створити новий елемент, якого ще немає в HTML? Або видалити існуючий? Сьогодні розберемо, як JavaScript може повністю керувати структурою сторінки.
createElement — створення елементів
Метод document.createElement(tag) створює новий HTML-елемент у пам'яті. Він ще не з'являється на сторінці — лише існує в JavaScript:
const paragraph = document.createElement("p");
// Елемент створено, але він поки "в повітрі" — не на сторінці
console.log(paragraph); // <p></p>
Після створення можна налаштувати елемент — додати текст, класи, атрибути:
const card = document.createElement("div");
card.textContent = "Привіт, я нова картка!";
card.classList.add("card", "card--primary");
card.setAttribute("data-id", "42");
// Елемент готовий, але досі не на сторінці
Спочатку повністю налаштуй елемент (текст, класи, атрибути), а потім додавай на сторінку. Це ефективніше, бо браузер перемальовує сторінку тільки один раз.
Додавання елементів на сторінку
appendChild — додати в кінець
const list = document.querySelector(".todo-list");
const item = document.createElement("li");
item.textContent = "Вивчити DOM";
list.appendChild(item); // додає <li> в кінець списку
append та prepend
Сучасніші методи з більшими можливостями:
const container = document.querySelector(".container");
const title = document.createElement("h2");
title.textContent = "Заголовок";
const text = document.createElement("p");
text.textContent = "Опис";
// append — додає в кінець (може кілька елементів + текст)
container.append(title, text, "Просто текст");
// prepend — додає на початок
const notice = document.createElement("div");
notice.textContent = "Увага!";
container.prepend(notice);
before та after — поруч з елементом
const secondItem = document.querySelector(".item:nth-child(2)");
const newItem = document.createElement("div");
newItem.textContent = "Новий елемент";
secondItem.before(newItem); // вставити ПЕРЕД другим елементом
secondItem.after(newItem); // вставити ПІСЛЯ другого елемента
Порівняння методів додавання
| Метод | Куди додає | Приймає |
|---|---|---|
parent.appendChild(el) | В кінець parent | Тільки один елемент |
parent.append(el, ...) | В кінець parent | Елементи + текст |
parent.prepend(el, ...) | На початок parent | Елементи + текст |
el.before(el2, ...) | Перед el | Елементи + текст |
el.after(el2, ...) | Після el | Елементи + текст |
Видалення елементів
remove() — видалити елемент
const notification = document.querySelector(".notification");
notification.remove(); // елемент зникає зі сторінки
removeChild() — видалити дочірній
Старіший метод, іноді потрібний:
const list = document.querySelector("ul");
const firstItem = list.querySelector("li");
list.removeChild(firstItem); // видаляє перший <li> зі списку
remove() з'явився у сучасних браузерах. Старий підхід — parent.removeChild(child). У сучасному коді використовуй remove().
cloneNode — клонування елементів
Іноді простіше скопіювати існуючий елемент, ніж створювати новий з нуля:
const original = document.querySelector(".card");
// Поверхнева копія — тільки сам елемент, без дочірніх
const shallowCopy = original.cloneNode(false);
// Глибока копія — елемент з усім вмістом
const deepCopy = original.cloneNode(true);
document.querySelector(".container").append(deepCopy);
cloneNode(true) копіює HTML-структуру, але не копіює обробники подій, додані через addEventListener. Якщо потрібні обробники — додавай їх після клонування.
insertAdjacentHTML — вставка HTML-рядка
Коли потрібно вставити шматок HTML як рядок:
const container = document.querySelector(".container");
container.insertAdjacentHTML("beforeend", "<p class='note'>Нова нотатка</p>");
Чотири позиції вставки:
<!-- beforebegin -->
<div class="container">
<!-- afterbegin -->
<p>Існуючий контент</p>
<!-- beforeend -->
</div>
<!-- afterend -->
const box = document.querySelector(".box");
box.insertAdjacentHTML("beforebegin", "<h2>Перед box</h2>");
box.insertAdjacentHTML("afterbegin", "<p>Перший дочірній</p>");
box.insertAdjacentHTML("beforeend", "<p>Останній дочірній</p>");
box.insertAdjacentHTML("afterend", "<footer>Після box</footer>");
insertAdjacentHTML має ту саму проблему, що й innerHTML — не вставляй сюди дані від користувача без перевірки (ризик XSS-атаки). Для тексту безпечніше використовувати createElement + textContent.
DocumentFragment — batch-операції
Коли потрібно додати багато елементів, кожен append змушує браузер перемальовувати сторінку. DocumentFragment — це невидимий контейнер, який дозволяє зібрати всі елементи разом, а потім додати їх одним рухом:
const list = document.querySelector(".list");
const fruits = ["Яблуко", "Банан", "Апельсин", "Манго", "Ківі"];
const fragment = document.createDocumentFragment();
fruits.forEach((fruit) => {
const li = document.createElement("li");
li.textContent = fruit;
li.classList.add("list-item");
fragment.appendChild(li); // додаємо у fragment, а не на сторінку
});
list.appendChild(fragment); // одна операція — одне перемалювання
Для невеликої кількості елементів (5-10) різниця непомітна. Але для сотень елементів DocumentFragment значно швидший. Це хороша звичка для будь-якої кількості.
Практика: динамічний список
Побудуємо список користувачів з масиву даних:
<div id="app">
<h2>Список користувачів</h2>
<ul class="user-list"></ul>
</div>
const users = [
{ name: "Олексій", role: "Розробник" },
{ name: "Марія", role: "Дизайнер" },
{ name: "Андрій", role: "Менеджер" },
{ name: "Катерина", role: "Тестувальник" },
];
const userList = document.querySelector(".user-list");
const fragment = document.createDocumentFragment();
users.forEach((user) => {
const li = document.createElement("li");
li.classList.add("user-item");
const nameSpan = document.createElement("span");
nameSpan.textContent = user.name;
nameSpan.classList.add("user-name");
const roleSpan = document.createElement("span");
roleSpan.textContent = user.role;
roleSpan.classList.add("user-role");
li.append(nameSpan, " — ", roleSpan);
fragment.appendChild(li);
});
userList.appendChild(fragment);
Підсумок
createElement(tag)— створює елемент у пам'ятіappend / prepend— додають в кінець / на початок батьківського елементаbefore / after— вставляють поруч з елементомremove()— видаляє елемент зі сторінкиcloneNode(true)— глибока копія елемента з вмістомinsertAdjacentHTML— вставка HTML-рядка у чотири позиціїDocumentFragment— збирає елементи перед вставкою (одне перемалювання)
Що далі?
У наступному уроці вивчимо події — як JavaScript реагує на дії користувача: кліки, наведення миші та інше.
Корисні посилання:
- javascript.info: Зміна документа — повний огляд маніпуляції DOM (українською)
- MDN: Document.createElement() — документація
- MDN: DocumentFragment — для оптимізації batch-вставок