Как получить соседний элемент js
Перейти к содержимому

Как получить соседний элемент js

  • автор:

Навигация по DOM элементам

Обход DOM или, проще говоря, навигация по DOM элементам — это работа со свойствами родительских, дочерних и соседних DOM элементов с помощью JavaScript.

В качестве примера мы будем использовать следующий код:

В браузере файл будет выглядеть следующим образом:

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

Объект document — это корень каждого узла в DOM. Следующий уровень — это объект window , который включает в себя закладки браузера, тулбары, функции promt и alert. Мы будем работать с DOM и, таким образом, с объектом document , который включает в себя все, что находится внутри window .

По умолчанию каждый документ содержит html , head , и body .

Проверить содержимое каждого элемента можно, набрав в консоли:

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

Как упоминалось ранее, узлы в DOM делятся на родительские, дочерние и соседние в зависимости от их связи с другими узлами. Родитель конкретного узла — это узел, который находится на уровень выше в иерархии DOM.

В нашем примере:

  • html является родителем head , body , и script
  • body является родителем h1 , h2 , p и ul , но не li , так как li на два уровня ниже body

Мы можем проверить родителя p элемента с помощью parentNode свойства. Так как мы присвоили p переменной, необходимо просто ввести:

Можно даже подняться на два уровня выше:

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

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

В данной статье мы будем работать со следующими свойствами: childNodes , firstChild , lastChild , children , firstElementChild и lastElementChild .

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

Возможно, вы ожидали, что вернется только три элемента li ? Текстовые узлы на самом деле пробелы, вызванные отступами между элементами, которые DOM воспринимает как узлы. Их не будет видно во вкладке Elements, так как консоль разработчика удаляет эти узлы автоматически.

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

Когда нам необходимо работать только с узлами элементов, можно использовать children , firstElement и lastElementChild .

ul.children вернет только три li элемента.

Для того, чтобы изменить только первый элемент li , используйте:

Так выглядит обновленная страница:

Если необходимо изменить все четыре дочерних элемента, вы можете использовать for .. of цикл следующим образом:

Теперь все дочерние элементы изменили цвет фона:

Если посмотреть на элемент p , мы увидим, что он содержит как текст, так и другой элемент (тег strong ).

Свойство childNodes полезно, когда необходимо получить доступ к информации.

Как childNodes , так и children возвращают не стандартный JavaScript массив (со всеми методами и свойствами), а объект, подобный массиву. Однако, как и с массивом, доступ к узлам можно получить через номер индекса или даже найти свойство length .

В этом коде мы получаем доступ к последнему дочернему элементу li из четырех элементов ul в body и применяем стили.

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

Соседние элементы

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

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

Получим средний элемент списка ul :

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

Изменения будут выглядеть следующим образом:

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

Навигация по DOM-элементам

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Более новая информация по этой теме находится на странице https://learn.javascript.ru/dom-navigation.

DOM позволяет делать что угодно с HTML-элементом и его содержимым, но для этого нужно сначала нужный элемент получить.

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

Так выглядят основные ссылки, по которым можно переходить между узлами DOM:

Посмотрим на них повнимательнее.

Сверху documentElement и body

Самые верхние элементы дерева доступны напрямую из document .

<HTML> = document.documentElement Первая точка входа – document.documentElement . Это свойство ссылается на DOM-объект для тега <html> . <BODY> = document.body Вторая точка входа – document.body , который соответствует тегу <body> .

В современных браузерах (кроме IE8-) также есть document.head – прямая ссылка на <head>

Нельзя получить доступ к элементу, которого ещё не существует в момент выполнения скрипта.

В частности, если скрипт находится в <head> , то в нём недоступен document.body .

Поэтому в следующем примере первый alert выведет null :

В мире DOM в качестве значения, обозначающего «нет такого элемента» или «узел не найден», используется не undefined , а null .

Дети: childNodes, firstChild, lastChild

Здесь и далее мы будем использовать два принципиально разных термина.

  • Дочерние элементы (или дети) – элементы, которые лежат непосредственно внутри данного. Например, внутри <HTML> обычно лежат <HEAD> и <BODY> .
  • Потомки – все элементы, которые лежат внутри данного, вместе с их детьми, детьми их детей и так далее. То есть, всё поддерево DOM.

Псевдо-массив childNodes хранит все дочерние элементы, включая текстовые.

Пример ниже последовательно выведет дочерние элементы document.body :

Обратим внимание на маленькую деталь. Если запустить пример выше, то последним будет выведен элемент <script> . На самом-то деле в документе есть ещё текст (обозначенный троеточием), но на момент выполнения скрипта браузер ещё до него не дошёл.

Пробельный узел будет в итоговом документе, но его ещё нет на момент выполнения скрипта.

Скажем больше – все навигационные свойства, которые перечислены в этой главе – только для чтения. Нельзя просто заменить элемент присвоением childNodes[i] = . .

Изменение DOM осуществляется другими методами, которые мы рассмотрим далее, все навигационные ссылки при этом обновляются автоматически.

Свойства firstChild и lastChild обеспечивают быстрый доступ к первому и последнему элементу.

При наличии дочерних узлов всегда верно:

Коллекции – не массивы

DOM-коллекции, такие как childNodes и другие, которые мы увидим далее, не являются JavaScript-массивами.

В них нет методов массивов, таких как forEach , map , push , pop и других.

Именно поэтому childNodes и называют «коллекция» или «псевдомассив».

Можно для перебора коллекции использовать обычный цикл for(var i=0; i<elems.length; i++) . Но что делать, если уж очень хочется воспользоваться методами массива?

Это возможно, основных варианта два:

Применить метод массива через call/apply :

При помощи Array.prototype.slice сделать из коллекции массив.

Обычно вызов arr.slice(a, b) делает новый массив и копирует туда элементы arr с индексами от a до b-1 включительно. Если же вызвать его без аргументов arr.slice() , то он делает новый массив и копирует туда все элементы arr .

Это работает и для коллекции:

Ранее мы говорили, что не рекомендуется использовать для перебора массива цикл for..in .

Коллекции – наглядный пример, почему нельзя. Они похожи на массивы, но у них есть свои свойства и методы, которых в массивах нет.

К примеру, код ниже должен перебрать все дочерние элементы <html> . Их, естественно, два: <head> и <body> . Максимум, три, если взять ещё и текст между ними.

Но в примере ниже alert сработает не три, а целых 5 раз!

Цикл for..in выведет не только ожидаемые индексы 0 , 1 , 2 , по которым лежат узлы в коллекции, но и свойство length (в коллекции оно enumerable), а также функцию item(n) – она никогда не используется, возвращает n-й элемент коллекции, проще обратиться по индексу [n] .

В реальном коде нам нужны только элементы, мы же будем работать с ними, а служебные свойства – не нужны. Поэтому желательно использовать for(var i=0; i<elems.length; i++) .

Соседи и родитель

Доступ к элементам слева и справа данного можно получить по ссылкам previousSibling / nextSibling .

Родитель доступен через parentNode . Если долго идти от одного элемента к другому, то рано или поздно дойдёшь до корня DOM, то есть до document.documentElement , а затем и document .

Навигация только по элементам

Навигационные ссылки, описанные выше, равно касаются всех узлов в документе. В частности, в childNodes сосуществуют и текстовые узлы и узлы-элементы и узлы-комментарии, если есть.

Но для большинства задач текстовые узлы нам не интересны.

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

Эти ссылки похожи на те, что раньше, только в ряде мест стоит слово Element :

  • children – только дочерние узлы-элементы, то есть соответствующие тегам.
  • firstElementChild , lastElementChild – соответственно, первый и последний дети-элементы.
  • previousElementSibling , nextElementSibling – соседи-элементы.
  • parentElement – родитель-элемент.

Свойство elem.parentNode возвращает родитель элемента.

Оно всегда равно parentElement , кроме одного исключения:

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

Модифицируем предыдущий пример, применив children вместо childNodes .

Теперь он будет выводить не все узлы, а только узлы-элементы:

Всегда верны равенства:

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

С точки зрения стандарта это ошибка, но IE8- также включает в children узлы, соответствующие HTML-комментариям.

Это может привести к сюрпризам при использовании свойства children , поэтому HTML-комментарии либо убирают либо используют фреймворк, к примеру, jQuery, который даёт свои методы перебора и отфильтрует их.

Особые ссылки для таблиц

У конкретных элементов DOM могут быть свои дополнительные ссылки для большего удобства навигации.

Здесь мы рассмотрим таблицу, так как это важный частный случай и просто для примера.

В списке ниже выделены наиболее полезные:

  • table.rows – коллекция строк TR таблицы.
  • table.caption/tHead/tFoot – ссылки на элементы таблицы CAPTION , THEAD , TFOOT .
  • table.tBodies – коллекция элементов таблицы TBODY , по спецификации их может быть несколько.
  • tbody.rows – коллекция строк TR секции.
  • tr.cells – коллекция ячеек TD/TH
  • tr.sectionRowIndex – номер строки в текущей секции THEAD/TBODY
  • tr.rowIndex – номер строки в таблице
  • td.cellIndex – номер ячейки в строке

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

Конечно же, таблицы – не исключение.

Аналогичные полезные свойства есть у HTML-форм, они позволяют из формы получить все её элементы, а из них – в свою очередь, форму. Мы рассмотрим их позже.

Интерактивное путешествие

Для того, чтобы убедиться, что вы разобрались с навигацией по DOM-ссылкам – вашему вниманию предлагается интерактивное путешествие по DOM.

Ниже вы найдёте документ (в ифрейме), и кнопки для перехода по нему.

Изначальный элемент – <html> . Попробуйте по ссылкам найти «информацию». Или ещё чего-нибудь.

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

DOM взять все соседние элементы

И естественно мне захотелось, что бы выбранный пункт меню подсвечивался, на что я написал такую строку, this.firstChild.style.color = «white»; , но если я нажму на второй пункт меню, первый так же останется белого цвета, как и вновь выбранный, единственное что я смог придумать, это взять все соседние элементы и на них повесить .style.color = «blue»; , но как выбрать все элементы и справа и слева? UPDATE

Для того, чтобы найти соседние элементы в DOM при помощи Vanilla JS, существуют специальные свойства у элемента:

  1. .nextSibling — возьмет следующий элемент на одном уровне дерева, если такого нет, то вернет null ;
  2. .previousSibling — возьмет предыдущий элемент на одном уровне дерева, если такого нет, то вернет null .

С их помощью можно построить циклы, которые соберут всех соседей, причём надо следить за тем, чтобы элемент был HTMLElement , а не текстовым узлом, например, вот так:

Если использовать jQuery, тогда взять все элементы можно просто вот так:

Вот небольшое сравнительное тестирование по времени. Странно, но почему-то в Хроме jQuery очень быстр, однако странно.

Walking the DOM

The DOM allows us to do anything with elements and their contents, but first we need to reach the corresponding DOM object.

All operations on the DOM start with the document object. That’s the main “entry point” to DOM. From it we can access any node.

Here’s a picture of links that allow for travel between DOM nodes:

Let’s discuss them in more detail.

On top: documentElement and body

The topmost tree nodes are available directly as document properties:

<html> = document.documentElement The topmost document node is document.documentElement . That’s the DOM node of the <html> tag. <body> = document.body Another widely used DOM node is the <body> element – document.body . <head> = document.head The <head> tag is available as document.head .

A script cannot access an element that doesn’t exist at the moment of running.

In particular, if a script is inside <head> , then document.body is unavailable, because the browser did not read it yet.

So, in the example below the first alert shows null :

In the DOM, the null value means “doesn’t exist” or “no such node”.

Children: childNodes, firstChild, lastChild

There are two terms that we’ll use from now on:

  • Child nodes (or children) – elements that are direct children. In other words, they are nested exactly in the given one. For instance, <head> and <body> are children of <html> element.
  • Descendants – all elements that are nested in the given one, including children, their children and so on.

For instance, here <body> has children <div> and <ul> (and few blank text nodes):

…And descendants of <body> are not only direct children <div> , <ul> but also more deeply nested elements, such as <li> (a child of <ul> ) and <b> (a child of <li> ) – the entire subtree.

The childNodes collection lists all child nodes, including text nodes.

The example below shows children of document.body :

Please note an interesting detail here. If we run the example above, the last element shown is <script> . In fact, the document has more stuff below, but at the moment of the script execution the browser did not read it yet, so the script doesn’t see it.

Properties firstChild and lastChild give fast access to the first and last children.

They are just shorthands. If there exist child nodes, then the following is always true:

There’s also a special function elem.hasChildNodes() to check whether there are any child nodes.

DOM collections

As we can see, childNodes looks like an array. But actually it’s not an array, but rather a collection – a special array-like iterable object.

There are two important consequences:

  1. We can use for..of to iterate over it:

That’s because it’s iterable (provides the Symbol.iterator property, as required).

  1. Array methods won’t work, because it’s not an array:

The first thing is nice. The second is tolerable, because we can use Array.from to create a “real” array from the collection, if we want array methods:

DOM collections, and even more – all navigation properties listed in this chapter are read-only.

We can’t replace a child by something else by assigning childNodes[i] = . .

Changing DOM needs other methods. We will see them in the next chapter.

Almost all DOM collections with minor exceptions are live. In other words, they reflect the current state of DOM.

If we keep a reference to elem.childNodes , and add/remove nodes into DOM, then they appear in the collection automatically.

Collections are iterable using for..of . Sometimes people try to use for..in for that.

Please, don’t. The for..in loop iterates over all enumerable properties. And collections have some “extra” rarely used properties that we usually do not want to get:

Siblings and the parent

Siblings are nodes that are children of the same parent.

For instance, here <head> and <body> are siblings:

  • <body> is said to be the “next” or “right” sibling of <head> ,
  • <head> is said to be the “previous” or “left” sibling of <body> .

The next sibling is in nextSibling property, and the previous one – in previousSibling .

The parent is available as parentNode .

Element-only navigation

Navigation properties listed above refer to all nodes. For instance, in childNodes we can see both text nodes, element nodes, and even comment nodes if they exist.

But for many tasks we don’t want text or comment nodes. We want to manipulate element nodes that represent tags and form the structure of the page.

So let’s see more navigation links that only take element nodes into account:

The links are similar to those given above, just with Element word inside:

  • children – only those children that are element nodes.
  • firstElementChild , lastElementChild – first and last element children.
  • previousElementSibling , nextElementSibling – neighbor elements.
  • parentElement – parent element.

The parentElement property returns the “element” parent, while parentNode returns “any node” parent. These properties are usually the same: they both get the parent.

With the one exception of document.documentElement :

The reason is that the root node document.documentElement ( <html> ) has document as its parent. But document is not an element node, so parentNode returns it and parentElement does not.

This detail may be useful when we want to travel up from an arbitrary element elem to <html> , but not to the document :

Let’s modify one of the examples above: replace childNodes with children . Now it shows only elements:

More links: tables

Till now we described the basic navigation properties.

Certain types of DOM elements may provide additional properties, specific to their type, for convenience.

Tables are a great example of that, and represent a particularly important case:

The <table> element supports (in addition to the given above) these properties:

  • table.rows – the collection of <tr> elements of the table.
  • table.caption/tHead/tFoot – references to elements <caption> , <thead> , <tfoot> .
  • table.tBodies – the collection of <tbody> elements (can be many according to the standard, but there will always be at least one – even if it is not in the source HTML, the browser will put it in the DOM).

<thead> , <tfoot> , <tbody> elements provide the rows property:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *