Раздел: Сайтостроение / JavaScript /
Дерево элементов DOM
Что такое JavaScript
Небольшая книга о JavaScript, которая поможет вам в изучении JavaScript. В книге и рассылке сведения для начинающих: что такое JavaScript, как это работает, письма, которые помогут принять решение, надо ли вам это или нет, а также полезные ссылки на обучающие материалы. Подробнее... |
Иногда требуется получить список всех элементов HTML-документа. В JavaScript это можно сделать рекурсивно, используя DOM API. В этой статье и видео кратко расскажу об этом и приведу пример обхода документа.
Как всегда напоминаю, что полный обучающий курс по JavaScript можно найти здесь:
>>> JavaScript, jQuery и Ajax с нуля до гуру >>>
DOM представляет HTML-документ в виде дерева объектов Node
. Для любой древовидной структуры наиболее часто приходится выполнять обход дерева с поочередным просмотром каждого узла. Один из способов приведён в примере:
<html> <!-- Тег 1 --> <head> <!-- Тег 2 --> <title>Примеры на JavaScript</title> <!-- Тег 3 --> <!-- Тег 4 --> <meta http-equiv=Content-Type content="text/html; charset=utf-8"> <!-- Тег 5 --> <meta name=Author content="Поляков А.В., info-master.su"> <script> //Тег 6 //Этой функции передается DOM-объект Node. //Функция проверяет, представляет ли этот узел HTML-тег, //то есть является ли узел объектом Element. //Функция рекурсивно вызывает сама себя для каждого дочернего узла, //проверяя их таким же образом. //Функция возвращает общее число найденных ею объектов Element. //Если вы вызываете эту функцию, передавая ей DOM-объект, //она выполнит обход всего DOM-дерева. function countTags(n) { //n – это Node var numtags = 0; //Инициализируем счетчик тегов if (n.nodeType == 1) //Проверяем, является ли n объектом Element numtags++; //Если это так, то увеличиваем счетчик //Теперь получаем все дочерние элементы n var children = n.childNodes; //Цикл по всем дочерним элементам for(var i = 0; i < children.length; i++) { //Рекурсия по всем дочерним элементам numtags += countTags(children[i]); } return numtags; //Возвращаем общее количество тегов } </script> </head> <!-- Это пример использования функции countTags() --> <body> <!-- Тег 7 --> Это <b> <!-- Тег 8 -->пример</b> документа.<br> <!-- Тег 9 --> <script> //Тег 10 document.write('Количество тегов в документе: ' + countTags(document)); </script> </body> </html>
В этом примере используется функция JavaScript, которая рекурсивно просматривает узел и все дочерние узлы и
подсчитывает количество HTML-тегов
(то есть узлов Element
), встреченных в процессе обхода.
Всего в этом примере документа 10 тегов (подписаны в комментариях). Обратите внимание на две вещи:
- В случае с парными тегами учитываются только открывающие теги.
- Тег
<script>
также учитывается.
Также обратите внимание на свойство childNodes
текущего узла.
Значением этого свойства является объект NodeList
, который в JavaScript ведёт себя как массив объектов
Node
. Поэтому функция может перечислить все дочерние узлы данного узла
путем циклического перебора элементов массива childNodes[]
.
Функция рекурсивно перечисляет не только все дочерние узлы данного узла, но и все узлы в дереве узлов.
Эта функция также показывает применение свойства nodeType
для определения типа каждого узла.
Есть ещё одно правило, которое в данном примере нарушено: нельзя обходить дерево документа или манипулировать им до тех пор, пока документ полностью не загружен. Правда, в нашем случае ничего страшного не произойдёт, потому что после того места, где выполняется сценарий, уже нет тегов - так что количество тегов будет подсчитано правильно.
Но вообще следовало бы вызвать функцию countTags(n)
из обработчика события onload
, например, так:
<body onload="alert('Количество тегов в документе: ' + countTags(document))">
В этом случае функция будет вызвана только после того, как документ будет полностью загружен, и сможет подсчитать количество всех тегов документа без ошибок (даже тех, которые находятся в документе после сценария).
В дополнение к свойству childNodes
интерфейс Node
определяет несколько других полезных свойств.
Свойства firstChild
и lastChild
ссылаются на первый и последний дочерние узлы, а свойства
nextSibling
и previousSibling
– на ближайшие смежные узлы.
Два узла называются смежными, если имеют один и тот же родительский узел.
Эти свойства предоставляют еще один способ обхода дочерних узлов, который показан в следующем примере:
<html> <head> <title>Примеры на JavaScript</title> <meta http-equiv=Content-Type content="text/html; charset=utf-8"> <meta name=Author content="Поляков А.В., info-master.su"> <script> var strings = []; //Эта рекурсивная функция отыскивает все узлы комментариев //и добавляет их содержимое в конец массива strings. function getStrings(n) { if (n.nodeType == 8) strings.push(n.data); else { for(var m = n.firstChild; m != null; m = m.nextSibling) { getStrings(m); } } } function getComment(n) { getStrings(n); return strings.join(";"); } </script> </head> <body onload="alert('Комментарии в HTML-документе: ' + getComment(document))"> <!-- Комментарий 1 --> <p> Это пример документа. </p> <!-- Комментарий 2 --> <p> Второй абзац </p> </body> </html>
В этом примере приводится определение функции getComment()
, которая отыскивает все узлы с комментариями, вложенные в указанный узел. Она извлекает и объединяет текстовое содержимое узлов и возвращает полученный результат в виде JavaScript-строки. В итоге данный пример выведет такое сообщение:
Ну и напоследок приведу список констант, определяющих тип узла:
Константа | Значение | Описание |
ELEMENT_NODE | 1 | Элемент |
ATTRIBUTE_NODE | 2 | Атрибут |
TEXT_NODE | 3 | Текст |
CDATA_SECTION_NODE | 4 | Узел CDATASection (интерфейс представляет раздел CDATA, который может использоваться в XML) |
ENTITY_REFERENCE_NODE | 5 | Сущности XML (???) |
ENTITY_NODE | 6 | Сущности XML (???) |
PROCESSING_INSTRUCTION_NODE | 7 | ProcessingInstruction XML документа (инструкция по обработке встраивает в XML инструкции, относящиеся к конкретному приложению, которые могут игнорироваться другими приложениями, не распознающими их) |
COMMENT_NODE | 8 | Комментарий |
DOCUMENT_NODE | 9 | Корневой узел дерева DOM |
DOCUMENT_TYPE_NODE | 10 | Тип документа |
DOCUMENT_FRAGMENT_NODE | 11 | Узел DocumentFragment (представляет собой минимальный объект документа, который не имеет родителя) |
NOTATION_NODE | 11 | Примечание (???) |
Не все эти константы поддерживаются. Также некоторые браузеры могут вообще не понимать имён (в этом случае надо использовать непосредственные значения, как в примерах выше). Поведение браузеров при обходе узлов также может отличаться.
Эта статья - лишь капля в море знаний о JavaScript. Если хотите испить эту чашу до дна, то изучить этот язык, а также jQuery и Ajax можно здесь:
>>> JavaScript, jQuery и Ajax с нуля до гуру >>>
Вступить в группу "Основы программирования"
Подписаться на канал в РУТУБ Подписаться на Дзен-канал Подписаться на рассылки по программированию |
Программирование на JavaScript
Видеокурс о программировании на JavaScript. Содержит 8 больших разделов от основ до работы с сетевыми запросами. В комплекте 5 подарков - мини-курсов по темам, связанным с сайтостроением. 72 урока продолжительностью более 13 часов. Упражнения и примеры исходных кодов. Поддержка от автора. Подробнее... |