Поехали!
Поиск пути
Прежде чем найти элементы и работать с ними, важно понять, где они находятся. Самый простой способ решить эту проблему — начать сверху и постепенно спускаться, что мы и сделаем.
Вид вершины нашей DOM представлен элементами window, document и html (рис. 28.2).
Рис. 28.2. Вид вершины этого дерева всегда одинаков
В связи с повышенной важностью этих трех элементов DOM предоставляет к ним легкий доступ посредством window, document и document.documentElement:
let windowObject = window; // хм-м….
let documentObject = document; // Это наверняка необязательно
let htmlElement = document.documentElement;
Здесь стоит отметить, что и window, и document являются глобальными свойствами. Нам не обязательно явно объявлять их подобно тому, как сделал я. Используйте их сразу.
Как только мы спускаемся ниже уровня HTML-элемента, наша DOM начинает ветвление и становится гораздо интереснее. С этого места можно использовать несколько способов навигации. Один из них мы уже видели многократно, и связан он с использованием querySelector и querySelectorAll для получения в точности тех элементов, которые нам нужны. На практике зачастую эти два метода слишком ограничены.
Иногда мы не знаем, куда именно нужно направиться. В этом случае методы querySelector и querySelectorAll уже не помогут. Нам просто нужно сесть за руль и ехать в надежде, что удастся найти то, что мы ищем. Когда дело доходит до навигации по DOM, мы зачастую будем оказываться в подобном положении. Именно здесь нам и помогут различные свойства, предлагаемые DOM, которые мы изучим далее.
Разобраться нам поможет знание того, что все элементы в DOM имеют по меньшей мере одну комбинацию родителей, братьев (соседних элементов) и потомков, на которых можно ориентироваться. Для наглядного представления посмотрите на ряд, содержащий элементы div и script, как показано на рис. 28.3.
Элементы div и script являются братьями, так как имеют одного родителя — элемент body. Элемент script не имеет потомков, но у div, напротив, они есть. Img, h1, p и div являются потомками элемента div, при этом все потомки одного родителя между собой являются братьями. Как и в реальной жизни, положение родителя, потомка и брата зависит от того, на какой части дерева мы фокусируемся. То есть практически каждый элемент в зависимости от угла обзора может выступать в различных ролях.
Для упрощения работы с этим всем у нас есть несколько свойств, на которые мы и будем полагаться. Ими являются firstChild, lastChild, parentNode, children, previousSibling и nextSibling. Просто глядя на их названия, вы можете догадаться, какую именно роль они играют. Дьявол в деталях, поэтому рассмотрим все подробно.
Рис. 28.3. Пример нашего дерева с родителями, братьями и потомками
Работа с братьями и родителями
Из всех свойств легче всего работать с относящимися к родителям и братьям, а именно parentNode, previousSibling и nextSibling. Схема на рис. 28.4 дает представление о том, как эти свойства работают.
Рис. 28.4. Связь между братьями и родителями с позиции DOM
Схема несколько перегружена, но понять, что на ней происходит, можно. Свойство parentNode указывает на родителя элемента. Свойства previousSibling и nextSibling позволяют элементу найти его предыдущего или следующего брата — если мы будем следовать по стрелкам на рисунке, то увидим это. В нижней строке nextSibling нашего img это div. previousSibling для div — это img. Обращение к parentNode в любом из этих элементов приведет вас к родителю div во втором ряду. Здесь все достаточно понятно.
Давай заведем детей!
Менее понятно, как во все это вписываются потомки. Поэтому давайте взглянем на свойства firstChild, lastChild и children, показанные на рис. 28.5.
Рис. 28.5. Представление потомков и их потомков
Свойства firstChild и lastChild относятся к первому и последнему дочерним элементам родителя. Если у родителя есть всего один потомок, как в случае с элементом body из нашего примера, тогда и firstChild, и lastChild будут указывать на одно и то же. Если у элемента нет потомков, то эти свойства будут возвращать null.
Самое хитрое из всех этих свойств — свойство children. Когда вы обращаетесь к свойству children в родителе, то по умолчанию получаете коллекцию дочерних элементов, которые у него есть. Эта коллекция не является Array, но при этом имеет некоторые присущие массиву возможности. Как и в случае с массивом, вы можете перебирать эту коллекцию или обращаться к ее потомкам по отдельности. У этой коллекции есть свойство length, которое сообщает, с каким количеством потомков взаимодействует родитель. Если у вас уже голова пошла кругом, не переживайте. Код из следующего раздела прояснят сказанное.