Пошук уроків, статей та іншого контенту
Освоїте навігацію між батьківськими, дочірніми та сусідніми вузлами DOM.
DOM подає HTML-документ у вигляді дерева вузлів. Кожен HTML-елемент може мати:
батьківський вузол;
дочірні вузли;
сусідні вузли на тому самому рівні.
Наприклад, для такої структури:
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>елемент ul є батьківським для всіх li, а кожен li має сусідні елементи.
Навігація DOM дає змогу перейти від одного знайденого елемента до іншого без повторного пошуку всього документа.
parentElementВластивість parentElement повертає батьківський HTML-елемент.
<div class="card">
<h2>JavaScript</h2>
</div>
<script>
const heading = document.querySelector('h2');
console.log(heading.parentElement);
</script>Результатом буде елемент:
<div class="card">
<h2>JavaScript</h2>
</div>За потреби можна піднятися на кілька рівнів:
const heading = document.querySelector('h2');
const card = heading.parentElement;
const body = card.parentElement;
console.log(body);parentNodeparentNode також повертає батьківський вузол:
const heading = document.querySelector('h2');
console.log(heading.parentNode);У більшості випадків для роботи з HTML використовують parentElement, оскільки він повертає саме елемент.
Різниця помітна тоді, коли батьківським вузлом є не HTML-елемент, а, наприклад, документ. Вузол Document не є елементом, тому parentElement у такому випадку поверне null.
childrenВластивість children повертає колекцію дочірніх HTML-елементів.
<ul class="topics">
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
<script>
const list = document.querySelector('.topics');
console.log(list.children);
console.log(list.children.length);
</script>Щоб отримати конкретний дочірній елемент, можна використати індекс:
const list = document.querySelector('.topics');
const firstTopic = list.children[0];
const secondTopic = list.children[1];
console.log(firstTopic.textContent);
console.log(secondTopic.textContent);Індексація починається з нуля, тому:
children[0] — перший дочірній елемент;
children[1] — другий дочірній елемент;
children[2] — третій дочірній елемент.
firstElementChild і lastElementChildЩоб отримати перший або останній дочірній елемент, зручно використовувати спеціальні властивості:
const list = document.querySelector('.topics');
console.log(list.firstElementChild);
console.log(list.lastElementChild);Якщо елемент не має дочірніх елементів, ці властивості повернуть null.
const emptyBlock = document.querySelector('.empty');
console.log(emptyBlock.firstElementChild); // nullchildNodesВластивість childNodes повертає всі дочірні вузли, а не лише HTML-елементи.
До вузлів можуть належати:
елементи;
текстові вузли;
коментарі.
<ul class="topics">
<li>HTML</li>
<li>CSS</li>
</ul>
<script>
const list = document.querySelector('.topics');
console.log(list.childNodes);
</script>У результаті можуть бути текстові вузли, що відповідають пробілам і перенесенням рядків у HTML.
Для роботи саме з HTML-елементами зазвичай краще використовувати children, firstElementChild і lastElementChild.
Сусідніми називають елементи, які мають одного батька.
Для переходу між сусідніми HTML-елементами використовують:
previousElementSibling — попередній сусідній елемент;
nextElementSibling — наступний сусідній елемент.
<ul class="topics">
<li>HTML</li>
<li class="active">CSS</li>
<li>JavaScript</li>
</ul>
<script>
const activeTopic = document.querySelector('.active');
console.log(activeTopic.previousElementSibling.textContent);
console.log(activeTopic.nextElementSibling.textContent);
</script>Результат:
HTML
JavaScriptЯкщо сусіднього елемента немає, властивість повертає null:
const firstTopic = document.querySelector('.topics').firstElementChild;
console.log(firstTopic.previousElementSibling); // nullДля роботи з будь-якими вузлами існують властивості:
previousSibling — попередній вузол;
nextSibling — наступний вузол;
parentNode — батьківський вузол;
childNodes — усі дочірні вузли.
Наприклад:
const activeTopic = document.querySelector('.active');
console.log(activeTopic.previousSibling);
console.log(activeTopic.nextSibling);Між елементами в HTML часто є пробіли або перенесення рядків. Тому previousSibling або nextSibling можуть повернути текстовий вузол, а не сусідній li.
Саме тому під час навігації між HTML-елементами частіше використовують previousElementSibling і nextElementSibling.
У наступному прикладі кнопки переміщують клас active між пунктами списку.
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<title>Навігація DOM</title>
<style>
li {
margin: 8px 0;
}
.active {
color: darkblue;
font-weight: bold;
}
</style>
</head>
<body>
<h1>Теми курсу</h1>
<ul id="topics">
<li class="active">HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
<button id="previousButton">Попередня тема</button>
<button id="nextButton">Наступна тема</button>
<script>
const list = document.querySelector('#topics');
const previousButton = document.querySelector('#previousButton');
const nextButton = document.querySelector('#nextButton');
function getActiveTopic() {
return list.querySelector('.active');
}
function showTopic(topic) {
if (!topic) {
return;
}
const currentTopic = getActiveTopic();
currentTopic.classList.remove('active');
topic.classList.add('active');
}
nextButton.addEventListener('click', () => {
const activeTopic = getActiveTopic();
const nextTopic = activeTopic.nextElementSibling;
showTopic(nextTopic);
});
previousButton.addEventListener('click', () => {
const activeTopic = getActiveTopic();
const previousTopic = activeTopic.previousElementSibling;
showTopic(previousTopic);
});
</script>
</body>
</html>Коли активним є перший пункт, previousElementSibling повертає null. Функція showTopic перевіряє це значення і не виконує зміни.
Перед використанням властивостей сусіднього елемента варто переконатися, що він існує.
Небезпечний варіант:
const firstItem = document.querySelector('li');
console.log(firstItem.previousElementSibling.textContent);У першого елемента немає попереднього сусіда. Тому значення previousElementSibling дорівнює null, а звернення до textContent спричинить помилку.
Безпечний варіант:
const firstItem = document.querySelector('li');
const previousItem = firstItem.previousElementSibling;
if (previousItem) {
console.log(previousItem.textContent);
} else {
console.log('Попереднього елемента немає');
}Також можна використати optional chaining:
const firstItem = document.querySelector('li');
console.log(firstItem.previousElementSibling?.textContent);Якщо сусіднього елемента немає, вираз поверне undefined, а не спричинить помилку.
Навігацію можна поєднувати з іншими операціями.
<div class="card">
<h2>Назва картки</h2>
<p>Опис картки</p>
</div>
<script>
const heading = document.querySelector('h2');
const description = heading.parentElement.children[1];
console.log(description.textContent);
</script>Послідовність дій:
Знайти h2.
Перейти до його батька за допомогою parentElement.
Отримати другого дочірнього елемента через children[1].
const currentItem = document.querySelector('.active');
const nextItem = currentItem.nextElementSibling;
if (nextItem) {
nextItem.textContent = 'Оновлений пункт';
}Колекцію children можна перебрати циклом:
const list = document.querySelector('#topics');
for (const topic of list.children) {
console.log(topic.textContent);
}Також можна використати Array.from, якщо потрібні методи масивів:
const list = document.querySelector('#topics');
const topics = Array.from(list.children);
const topicNames = topics.map((topic) => topic.textContent);
console.log(topicNames);Element і Node: що вибратиУ повсякденній роботі з HTML запам’ятайте таке правило:
parentElement, children, firstElementChild, lastElementChild;
previousElementSibling, nextElementSibling
використовують, коли потрібні саме HTML-елементи.
А властивості:
parentNode, childNodes;
previousSibling, nextSibling
використовують, коли потрібно працювати з усіма типами DOM-вузлів.
Наприклад, якщо треба перейти до сусіднього li, використовуйте:
item.nextElementSibling;а не:
item.nextSibling;Так код не залежатиме від пробілів і перенесень рядків у HTML.
children і childNodeschildren містить лише елементи:
element.children;childNodes може містити текстові вузли та коментарі:
element.childNodes;Для типової навігації між HTML-елементами обирайте children.
nullУ першого елемента немає попереднього сусіда, а в останнього — наступного:
const firstItem = document.querySelector('li');
console.log(firstItem.previousElementSibling); // nullПеред зверненням до властивостей результату перевіряйте його існування.
Якщо список має три елементи, індекси будуть 0, 1 і 2.
const list = document.querySelector('ul');
console.log(list.children[3]); // undefinedВластивості навігації лише повертають вузол. Вони не змінюють документ:
const nextItem = currentItem.nextElementSibling;Щоб змінити знайдений елемент, потрібно виконати додаткову операцію:
nextItem.classList.add('active');Якщо JavaScript виконується до створення HTML-елементів, querySelector може повернути null.
Розміщуйте script перед закривальним тегом body або використовуйте атрибут defer:
<script src="script.js" defer></script>DOM має деревоподібну структуру: батьківські, дочірні та сусідні вузли.
parentElement повертає батьківський HTML-елемент.
children містить дочірні HTML-елементи.
firstElementChild і lastElementChild повертають перший та останній дочірні елементи.
previousElementSibling і nextElementSibling дають змогу переходити між сусідніми елементами.
parentNode, childNodes, previousSibling і nextSibling працюють з усіма типами DOM-вузлів.
Для навігації між HTML-елементами зазвичай краще використовувати властивості з суфіксом Element.
Якщо потрібного сусіда немає, властивість повертає null, тому результат потрібно перевіряти.