Навигация по DOM

В предыдущем мануале – Доступ к элементам в DOM – вы узнали, как использовать встроенные методы объекта document для доступа к элементам HTML по идентификатору, классу, имени тега и селекторам запросов. Как вы уже знаете, DOM структурирован как дерево узлов: в корне находится узел document, а остальные узлы (включая элементы, комментарии и текстовые узлы) представляют ветки.

Читайте также: Дерево и узлы DOM

Часто вам нужно будет перемещаться по DOM без предварительного указания каждого элемента. Умение перемещаться вверх и вниз по дереву DOM и переходить от ветки к ветке необходимо для понимания того, как работать с JavaScript и HTML.

В этом мануале речь пойдет о навигации по DOM с помощью свойств родительских, дочерних и соседних узлов.

Подготовка

Для начала создайте файл nodes.html и добавьте в него такой код:

<!DOCTYPE html>
<html>
<head>
<title>Learning About Nodes</title>
<style>
* { border: 2px solid #dedede; padding: 15px; margin: 15px; }
html { margin: 0; padding: 0; }
body { max-width: 600px; font-family: sans-serif; color: #333; }
</style>
</head>
<body>
<h1>Shark World</h1>
<p>The world’s leading source on <strong>shark</strong> related information.</p>
<h2>Types of Sharks</h2>
<ul>
<li>Hammerhead</li>
<li>Tiger</li>
<li>Great White</li>
</ul>
</body>
<script>
const h1 = document.getElementsByTagName (‘h1’)[0];
const p = document.getElementsByTagName (‘p’)[0];
const ul = document.getElementsByTagName (‘ul’)[0];
</script>
</html>

Загрузите эту страницу в браузере и убедитесь, что она работает.

На этом тестовом сайте есть HTML-документ с несколькими элементами. Некоторые базовые CSS добавлены в тег style, чтобы каждый элемент был явно видимым, а несколько переменных были созданы в script для удобства доступа к нескольким элементам. Поскольку для h1, p и ul существует только один элемент, вы можете получить доступ к первому индексу каждого соответствующего свойства getElementsByTagName.

Корневые узлы

Объект document является корнем для каждого узла в DOM. Этот объект фактически является свойством объекта window, который является глобальным объектом верхнего уровня, представляющим вкладку в браузере. Объект window имеет доступ к такой информации, как панель инструментов, высота и ширина окна, подсказки и предупреждения. Документ состоит из того, что находится внутри объекта window.

В этой таблице перечислены корневые элементы, которые будет содержать каждый документ. Даже если в браузер загружен пустой HTML-файл, эти узлы будут добавлены и проанализированы в DOM.

Свойство Узел Тип узла
document #document DOCUMENT_NODE
document.documentElement html ELEMENT_NODE
document.head head ELEMENT_NODE
document.body body ELEMENT_NODE

Поскольку элементы html, head и body очень распространены, они имеют свои собственные свойства в документе.

Откройте консоль в DevTools и проверьте каждое из этих четырех свойств. Вы также можете проверить h1, p и ul, которые возвратят элементы благодаря переменным, которые добавлены в тег script.

Родительские узлы

Узлы в DOM бывают родительскими, дочерними и соседними в зависимости от их отношения к другим узлам. Родительским называется узел, который находится на уровень выше других узлов (или ближе к document в иерархии DOM). Существует два свойства для получения родительских узлов – parentNode и parentElement.

Свойство Результат
parentNode Родительский узел
parentElement Узел родительского элемента

В файле nodes.html:

  • html – родитель узлов head, body и script.
  • body – родитель h1, h2, p и ul, но не li, поскольку li находится на два уровня ниже body.

Чтобы узнать, какой узел является родительским узлом элемента р, используйте свойство parentNode. Переменная р происходит из пользовательской декларации document.getElementsByTagName(‘p’)[0].

p.parentNode;
► <body>...</body>

Родительским узлом р является body, но как узнать родителя более высокого уровня? Для этого можно соединить свойства:

p.parentNode.parentNode;
► <html>...</html>

Используя parentNode дважды, вы можете получить родительский узел p более высокого порядка.

Есть два свойства для извлечения родительского узла, но между ними есть одно небольшое различие, как показано в этом фрагменте:

// Assign html object to html variable
const html = document.documentElement;
console.log(html.parentNode); // > #document
console.log(html.parentElement); // > null

Родителем почти любого узла будет узел элемента, поскольку текстовый узел и узел комментария не могут быть родителями других узлов. Однако родительский элемент html является узлом документа, поэтому parentElement возвращает значение null. Как правило, при обходе DOM используется parentNode.

Дочерние узлы

Дочерними называются узлы, которые находятся на уровень ниже. Любые узлы, находящиеся за пределами одного уровня вложения, обычно называются дочерними.

Свойство Результат
childNodes Дочерние узлы
firstChild Первый дочерний узел
lastChild Последний дочерний узел
children Дочерние узлы элемента
firstElementChild Первый дочерний узел элемента
lastElementChild Последний дочерний узел элемента

Свойство childNodes возвращает живой список дочерних узлов. кажется, что элемент ul получит три дочерних элемента li. Давайте проверим эту догадку.

ul.childNodes;
► (7) [text, li, text, li, text, li, text]

В дополнение к трем элементам li он также получает четыре текстовых узла. Это потому, что вы написали собственный HTML (он не был сгенерирован JavaScript), а отступы между элементами подсчитываются в DOM как текстовые узлы. Это неочевидно, так как вкладка Elements в DevTools удаляет узлы пробелов.

Если вы попробуете изменить цвет фона первого дочернего узла с помощью свойства firstChild, он вернет ошибку, потому что первым узлом является текст.

ul.firstChild.style.background = 'yellow';
Uncaught TypeError: Cannot set property 'background' of undefined

Свойства children, firstElementChild и lastElementChild существуют в подобных ситуациях только для извлечения узлов элемента. ul.children вернет только три элемента li.

Используя firstElementChild, вы можете изменить цвет фона первого li в ul.

ul.firstElementChild.style.background = 'yellow';

После запуска этого кода страница в браузере обновится и изменит цвет фона соответствующего узла.

При выполнении основных операций с DOM (как в этом примере) чрезвычайно полезны специфичные свойства элемента. В веб-приложениях, сгенерированных JavaScript, с большей вероятностью будут использоваться свойства, которые охватывают все узлы, поскольку в этом случае не будет новых строк и отступов.

Цикл for…of может итерировать все элементы children.

for (let element of ul.children) {
element.style.background = 'yellow';
}

После этого на странице изменится цвет фона всех дочерних элементов.

Элемент р имеет как текст, так и другие элементы, и свойство childNodes поможет извлечь эти данные:

for (let element of p.childNodes) {
console.log(element);
}
"The world's leading source on "
<strong>​shark​</strong>​
" related information."

childNodes и children не возвращают массивы со всеми свойствами и методами, но они ведут себя аналогично массивам JavaScript. Вы можете получить доступ к узлам по номеру индекса или найти их свойство length.

Читайте также:

document.body.children[3].lastElementChild.style.background = 'fuchsia';

Вышеприведенный код найдет последний элемент child (li) четвертого дочернего элемента (ul) для body и применит стиль.

Используя свойства родительских и дочерних узлов, вы можете получить любой узел в DOM.

Соседние узлы

Соседними называются узлы, которые находятся на одном уровне дерева DOM. Соседние узлы не обязательно должны быть узлами одного типа – текстовые узлы, узлы элементов и комментариев могут считаться соседними.

Свойство Результат
previousSibling Предыдущий соседний узел
nextSibling Следующий соседний узел
previousElementSibling Предыдущий соседний узел элемента
nextElementSibling Следующий соседний узел элемента

Свойства соседних узлов работают так же, как и дочерние узлы, поскольку тут существует набор свойств для навигации по всем узлам и набор свойств только для узлов элемента. previousSibling и nextSibling выводят предыдущий или последующий узел относительно указанного узла, а previousElementSibling и nextElementSibling выводят только узлы элемента.

В файле nodes.html попробуйте выбрать средний элемент ul:

const tiger = ul.children[1];

Поскольку этот DOM был создан с нуля и не как веб-приложение JavaScript, для доступа к предыдущему и следующему узлам элемента нужно использовать свойства соседних узлов (так как в DOM есть пробел).

tiger.nextElementSibling.style.background = 'coral';
tiger.previousElementSibling.style.background = 'aquamarine';

Запустив этот код, вы измените цвет фона Hammerhead и Great White.

Заключение

Теперь вы умеете обращаться к корневым узлам каждого HTML-документа и перемещаться по DOM с помощью свойств родительских, дочерних и соседних узлов.

Читайте также: Доступ к элементам в DOM

Tags: