Мастер-классы по Javascript Екатеринбург Ростов-на-Дону Москва Узнать больше...
Содержание (скрыть) Содержание (показать)

Основные свойства: тип, тег и содержимое узла

  1. Тип: nodeType
  2. Тег: nodeName и tagName
    1. Какая разница между tagName и nodeName ?
  3. innerHTML
    1. Тонкости innerHTML
  4. nodeValue/data
  5. Итого

В этой главе мы рассмотрим три основных свойства DOM-узлов: тип, тег и содержимое.

Мы увидим, какие значения они могут принимать и как с ними работать из JavaScript.

Тип: nodeType

С тремя типами мы уже встречались. Это 1) элемент, 2) текстовый узел и 3) комментарий.

На самом деле типов узлов гораздо больше. Строго говоря, их 12, и они описаны в спецификации DOM Уровень 1:

interface Node {
  // NodeType
  const unsigned short      ELEMENT_NODE       = 1;
  const unsigned short      ATTRIBUTE_NODE     = 2;
  const unsigned short      TEXT_NODE          = 3;
  const unsigned short      CDATA_SECTION_NODE = 4;
  const unsigned short      ENTITY_REFERENCE_NODE = 5;
  const unsigned short      ENTITY_NODE        = 6;
  const unsigned short      PROCESSING_INSTRUCTION_NODE = 7;
  const unsigned short      COMMENT_NODE       = 8;
  const unsigned short      DOCUMENT_NODE      = 9;
  const unsigned short      DOCUMENT_TYPE_NODE = 10;
  const unsigned short      DOCUMENT_FRAGMENT_NODE = 11;
  const unsigned short      NOTATION_NODE      = 12;   
  ...
}

Нам важны номера основных типов.

Самые важные — это ELEMENT_NODE под номером 1 и TEXT_NODE под номером 3.

Тип узла содержится в его свойстве nodeType.

Например, выведем все узлы-потомки document.body, являющиеся элементами:

<body>
  <div>Читатели:</div>
  <ul>
    <li>Вася</li>
    <li>Петя</li>
  </ul>
 
  <!-- комментарий -->

  <script>   
    var childNodes = document.body.childNodes;

    for (var i=0; i<childNodes.length; i++) {

*!*
      // отфильтровать не-элементы  
      if (childNodes[i].nodeType != 1) continue;
*/!*

      alert(childNodes[i]);

    }
  </script>
</body>

Что выведет скрипт на этой странице?

<!DOCTYPE HTML>
<html>  
<body>  
   <script>
      alert(document.body.lastChild.nodeType);
   </script>
</body>  
</html>

Решение
Решение

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

Так что результат будет 1 (узел-элемент).

<!DOCTYPE HTML>
<html>  
<body>  
   <script>
      alert(document.body.lastChild.nodeType);
   </script>
</body>  
</html>

Тег: nodeName и tagName

Существует целых два свойства: nodeName и tagName, которые содержат название(тег) элемента узла.

Название HTML-тега всегда находится в верхнем регистре.

Например, для document.body:

alert( document.body.nodeName );   // BODY
alert( document.body.tagName );   // BODY

Когда nodeName не в верхнем регистре?

У браузера есть два режима обработки документа: HTML и XML-режим. Обычно используется режим HTML, XML-режим включается, когда браузер получает XML-документ через XMLHttpRequest(технология AJAX) или при наличии заголовка Content-Type: application/xml+xhtml.

В XML-режиме сохраняется регистр и nodeName может выдать «body» или даже «bOdY» — в точности как указано в документе.

Какая разница между tagName и nodeName ?

Разница отражена в названиях свойств, но неочевидна.

  • Свойство nodeName определено для многих типов DOM-узлов.
  • Свойство tagName — есть только у элементов (в IE<9 также у комментариев, это ошибка в браузере).

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

Например:

<body><!-- комментарий -->

<script>
  // для комментария
  alert(document.body.firstChild.nodeName); // #comment
  alert(document.body.firstChild.tagName); // undefined (в IE<9 воскл. знак "!")

  // для документа
  alert(document.nodeName); // #document, т.к. корень DOM -- не элемент
  alert(document.tagName); // undefined
</script>
</body>

При работе только с узлами элементов имеет смысл использовать tagName — так короче Smile.

innerHTML

Свойство innerHTML описано в спецификации HTML 5 — embedded content.

Оно позволяет получить HTML-содержимое узла в виде строки. В innerHTML можно и читать и писать.

Пример выведет на экран все содержимое document.body, а затем заменит его на другое:

<body>
  <p>Параграф</p>
  <div>Div</div>

  <script>
    alert( document.body.innerHTML ); // читаем текущее содержимое
    document.body.innerHTML = 'Новый BODY!'; // заменяем содержимое
  </script>

</body>

При чтении innerHTML HTML-код всегда будет валиден. При записи — можно записать что угодно, браузер поправит некорректный HTML-код:

<body>

  <script>
    document.body.innerHTML = '<b>тест'; // незакрытый тег
    alert(document.body.innerHTML); // <b>тест</b> (исправлено)
  </script>

</body>

innerHTML — очень полезное свойство и одно из самых часто используемых.

Тонкости innerHTML

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

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

Для таблиц в IE — innerHTML только для чтения

В Internet Explorer, innerHTML доступно только для чтения для элементов COL, COLGROUP, FRAMESET, HEAD, HTML, STYLE, TABLE, TBODY, TFOOT, THEAD, TITLE, TR.

В частности, в IE нельзя присвоить innerHTML табличным элементам, кроме ячеек (TD/TH).

Добавление innerHTML+= осуществляет перезапись

Синтаксически, можно добавить текст к innerHTML через +=:

chatDiv.innerHTML += "<div>Привет<img src='smile.gif'/> !</div>";
chatDiv.innerHTML += "Как дела?";

На практике этим следует пользоваться с большой осторожностью, т.к. фактически добавления не происходит:

  1. Удаляется старое содержание
  2. На его место становится новое значение innerHTML.

Так как новое значение записывается с нуля, то все изображения и другие ресурсы будут перезагружены. В примере выше вторая строчка перезагрузит smile.gif, который был до неё.

Если в chatDiv много текста, то эта перезагрузка будет очень заметна.

К счастью, есть и другие способы добавить содержимое, не использующие innerHTML.

Скрипты не выполняются

Если в innerHTML есть тег script — он не будет выполнен. Пример — ниже:

<div id="my"></div>

<script>
  var elem = document.getElementById('my');
  elem.innerHTML = 'ТЕСТ<script>alert(1);</scr'+'ipt>';
</script>

В примере закрывающий тег </scr'+'ipt> разбит на две строки, т.к. иначе браузер подумает, что это конец скрипта. Вставленный скрипт не выполнится.

Исключение — IE, в нем вставляемый скрипт выполняются, если у него есть атрибут defer (это нестандартная возможность):

<div id="my"></div>

<script>
  var elem = document.getElementById('my');
  elem.innerHTML = 'Для IE<script *!*defer*/!*>alert(1);</scr'+'ipt>';
</script>

IE<9 обрезает style и script в начале innerHTML

Если скрипт или стиль находятся в начале innerHTML, то старый IE уберет их. Визуальный эффект очевиден — стили не применятся.

Открыть пример (в IE9 будет режим IE8).

Смотрите также innerHTML на MSDN на эту тему.

nodeValue/data

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

Оно доступно через два свойства: nodeValue и data. Следующий пример демонстрирует их:

<body>
  Привет
  <!-- Комментарий -->
  <script>
    for (var i=0; i<document.body.childNodes.length; i++) {
*!*
      alert(document.body.childNodes[i].nodeValue);
      alert(document.body.childNodes[i].data);
*/!*
    }
  </script>
</body>

В этом примере выводятся последовательно:

  1. Содержимое первого узла (текстового): Привет (2 раза).
  2. Содержимое второго узла (комментария): Комментарий (2 раза).
  3. Содержимого третьего узла (текста между комментарием и скриптом): (там пробелы, 2 раза)
  4. Свойство nodeValue=null для узла SCRIPT, так как это узел-элемент. А вот data=undefined. Это единственное различие в поведении этих свойств.

В документе после SCRIPT есть еще один текстовый узел, но на момент работы скрипта браузер дошел в разборе документа только до SCRIPT, поэтому он не выводится.

Итого

Основные свойства DOM-узлов:

nodeType
Тип узла. Самые популярные типы: "1" - для элементов и "3" - для текстовых узлов. Только для чтения.
nodeName/tagName
Название тега заглавными буквами. nodeName имеет специальные значения для узлов-неэлементов. Только для чтения.
innerHTML
Содержимое узла-элемента. Можно изменять.
nodeValue/data
Содержимое текстового узла или комментария. Свойство nodeValue также определено и для других типов узлов. Можно изменять.

Узлы DOM также имеют другие свойства, в зависимости от тега. Например, у INPUT есть свойства value и checked, а у A есть href и т.д. Мы рассмотрим их далее.

Что выведет этот код?

<script>
document.body.innerHTML = "<!-- " + document.body.tagName + " -->"
alert(document.body.firstChild.data);
</script>

Решение
Решение

Ответ: BODY.

  1. В <body> попадёт комментарий (Свойство tagName в HTML — всегда большими буквами).
  2. Этот комментарий будет первым потомком (и единственным).
  3. У комментария свойство data — его содержимое.


Комментарии

  1. Приветствуются комментарии, содержащие дополнения и вопросы по статье, и ответы на них.
  2. Если ваш комментарий касается задачи -- откройте её в отдельном окне и напишите там.
  3. Комментарии без смысла, с рекламой или не о статье вообще - удаляются.
Наверх

Содержание

Реклама

Нашли опечатку?

Нашли опечатку на сайте? Что-то кажется странным?
Выделите соответствующий текст и нажмите Ctrl+Enter!

Последние Комментарии

Помоги другим!

Помоги другим узнать о хорошей статье!