Раздел: Сайтостроение / JavaScript /

Дерево элементов DOM

Что такое JavaScript Что такое 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 тегов (подписаны в комментариях). Обратите внимание на две вещи:

  1. В случае с парными тегами учитываются только открывающие теги.
  2. Тег <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-строки. В итоге данный пример выведет такое сообщение:

Получение комментариев в HTML-документе с помощью 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 с Нуля до Гуру 2.0 Программирование на JavaScript

Видеокурс о программировании на JavaScript. Содержит 8 больших разделов от основ до работы с сетевыми запросами. В комплекте 5 подарков - мини-курсов по темам, связанным с сайтостроением. 72 урока продолжительностью более 13 часов. Упражнения и примеры исходных кодов. Поддержка от автора. Подробнее...
Инфо-МАСТЕР ®
Все права защищены ©
e-mail: mail@info-master.su

Яндекс.Метрика