У каждого DOM-элемента есть свойства, благодаря которым мы можем свободно перемещаться по иерархической структуре DOM-дерева.
Для облегчения понимания, изобразить эти свойства можно примерно так:
parentNode | previousSibling - node - nextSibling / \ firstChild lastChild
Описание:
node.parentNode; // родительский узел
node.previousSibling; // предыдущий, на этом же уровне, узел
node.nextSibling; // следующий, на этом же уровне, узел
node.firstChild; // первый дочерний элемент
node.lastChild; // последний дочерний элемент
Пример:
Допустим у нас есть html-фрагмент такой структуры:
<h1>Список</h1>
<div>
<ul id="myList">
<li>запись 1</li>
<li>запись 2</li>
<li>запись 3</li>
<li>запись 4</li>
</ul>
<em>Комментарий к списку</em>
</div>
// найдем список, по его идентификатору
var myList = document.getElementById("myList");
// !!! Следующий код не рабочий.
// !!! Он является всего лишь демонстрационным.
// !!! (см. примечание ниже - *)
// получим 2-ю запись в списке
var secondLi = myList.firstChild.nextSibling;
// получим заголовок <h1/>
var listH1 = myList.parentNode.previousSibling;
Таким вот нехитрым способом мы можем обойти всё DOM-дерево.
* Примечание: Этот код был бы работоспособным в том случае, если бы между тегами не было лишних пробелов, энтеров, табуляций. Красивое форматирование html-кода привело к тому, что между тегами появились текстовые узлы, состоящие из пустого пространства.
Решить эту проблему можно несколькими путями:
— учитывать (игнорировать) все текстовые узлы при обходе;
— генерировать html-код без таких узлов;
— рекурсивно удалить все пустые текстовые узлы с фрагмента html-кода, перед началом работы с ним.
Теговые узлы отличаются от текстовых узлов свойством nodeType. Для тега nodeType = 1, а для текстового узла nodeType = 3.
Владея этой информацией, можно написать свои аналогичные функции обхода, которые бы игнорировали все текстовые узлы:
// аналог parentNode
function parentTag(node) {
return node.parentNode;
}
// аналог previousSibling
function previousTag(node) {
var node = node.previousSibling;
return (node && node.nodeType!=1) ? previousTag(node) : node;
}
// аналог nextSibling
function nextTag(node) {
var node = node.nextSibling;
return (node && node.nodeType!=1) ? nextTag(node) : node;
}
// аналог firstChild
function firstChildTag(node) {
var node = node.firstChild;
return (node && node.nodeType!=1) ? nextTag(node) : node;
}
// аналог lastChild
function lastChildTag(node) {
var node = node.lastChild;
return (node && node.nodeType!=1) ? previousTag(node) : node;
}
Аналогичный пример, но с применением данных функций:
var myList = document.getElementById("myList");
// получим 2-ю запись в списке
var secondLi = nextTag(firstChildTag(myList));
// получим заголовок <h1/>
var listH1 = previousTag(parentTag(myList));
Для более удобного использования, данные функции могут быть реализованы в виде методов узлов.
Спасибо за статью! Очень классно и просто показано перемещение по узлам. В интернет-магазине для прикрутки одной функции именно это было нужно. Мне очень помогло это простое и понятное объяснение! Спасибо ещё раз! :)
спасибо!
Огромное спасибо!