В этой главе мы рассмотрим три основных свойства 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 — так короче
.
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 не так прост, как может показаться, и таит в себе некоторые тонкости, которые могут сбить с толку новичка, а иногда и опытного программиста.
Ознакомьтесь с ними. Даже если этих сложностей у вас пока нет, эта информация отложится где-то в мозге и поможет, когда проблема появится.
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 += "Как дела?";
На практике этим следует пользоваться с большой осторожностью, т.к. фактически добавления не происходит:
- Удаляется старое содержание
- На его место становится новое значение
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>
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>
В этом примере выводятся последовательно:
- Содержимое первого узла (текстового):
Привет(2 раза). - Содержимое второго узла (комментария):
Комментарий(2 раза). - Содержимого третьего узла (текста между комментарием и скриптом):
(там пробелы, 2 раза) - Свойство
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.
- В
<body>попадёт комментарий(СвойствоtagNameв HTML — всегда большими буквами). - Этот комментарий будет первым потомком (и единственным).
- У комментария свойство
data— его содержимое.
Комментарии
- Приветствуются комментарии, содержащие дополнения и вопросы по статье, и ответы на них.
- Если ваш комментарий касается задачи -- откройте её в отдельном окне и напишите там.
- Комментарии без смысла, с рекламой или не о статье вообще - удаляются.