HTML, Excel, Word, SEOОсновы JavaScript ⇒ Модель HTML документа

ОСНОВЫ JavaScript

Учебник JavaScript
·Знакомство с JS. Переменные, операторы, операции
·Функции
·Модель HTML документа
·Иерархия документов в бразуере
·Формы
·Окна и фреймы
·Ссылки, заголовок, статус
·События
·События клавиатуры и мыши
·События. Таймер
·Стили. Управление стилями
·Слои и блоки. Управление видимостью
·Объекты JS
·Внешние объекты
·Внутренние объекты
·Массивы
·Регулярные выражения
·Математика в JS
·Пример простого калькулятора
·Дата и время
·Cookies и хранение состояния
·Немного об AJAX
·Работа с WebMoney

 

Модель HTML документа



Элементы HTML. Вложенность элементов

Доступ к элементам

Как вы, наверное, помните из первой главы, DHTML базируется на трех вещах – JavaScript, HTML и CSS. 

Говорить о том, как связаны HTML и CSS, нет необходимости. Гораздо больший интерес представляет связь JavaScript с HTML. 

Для того чтобы понять, каким образом скрипты написанные на JS могут взаимодействовать с HTML-кодом, нужно для начала получить некоторые сведения об объектной модели документа (DOM). Собственно, изучением этой модели мы и займемся. 

Как вы знаете, текст на языке HTML может быть преобразована в древовидную структуру, содержащую HTML тэги. Любой тег может содержать еще несколько, те, в свою очередь – еще несколько. Ничего не напоминает? 

Да, так же точно я описывал объекты в JS. 

Собственно, после загрузки HTML кода в браузер он и разбивается в подобную структуру, и уже после этого отображается. 

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

Для унификации способов обращения к этим элементам (еще их называют NODE – узлы) и служит DOM. 

С точки зрения программиста на JS, DOM – это, во-первых, описание структуры элементов HTML (то есть – как именно браузер их преобразует во внутреннее представление), и, во-вторых, набор функций, служащих для работы с этими элементами. 

Элементы HTML. Вложенность элементов.

Каждый современный браузер обязательно имеет объект window.document.

Этот объект является отображением преобразованного HTML документа, и вся работа с DOM производится при помощи этого объекта (то есть – его свойств и методов). 

Любой HTML документ обязательно содержит тэг <html>. Именно этот тэг и становится «корнем» дерева, а все вложенные теги – его ветвями.

В DOM этот элемент доступен как window.document.documentElement (дальше я буду писать обращения к document без предварительного указания объекта window – надеюсь, вы помните, почему).

Этот элемент (как и большинство других элементов) имеет тип Element. Это специальный тип, добавленный к стандартным типам JS средствами DOM. Также, кроме типа Element, есть еще несколько типов (nodeList, attribute), которые используются исключительно при работе с DOM

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

Первый – это обход дерева. Любой элемент имеет ссылки на следующий и предыдущий элементы (если они есть), а также на первого и последнего потомка, кроме собственно списка потомков. И, кроме этого, любой элемент содержит ссылку на своего родителя. 

Используя только эти функции, можно записать любой путь к любому элементу относительно любого другого элемента. 

Также можно использовать специальные методы объекта document для поиска конкретного узла (или группы узлов). 

Возможно, некоторые термины – потомок, родитель – вам непонятны. Сейчас я постараюсь вам эти термины объяснить. 

Начнем с дерева. До этого вы сталкивались с массивами и объектами – в общем-то, линейными структурами. Дерево представляет собой другую структуру – она нелинейна. Для того чтобы понять, что это такое, представьте себе – да, дерево. Со стволом, листьями и ветками. В случае когда «дерево» это структура данных, сходство сохраняется. 

Любое дерево имеет главный элемент (или корень), откуда дерево, можно сказать, начинается. Этот элемент – обычный объект, с тем отличием, что он, кроме прочих свойств, также имеет массив ссылок на группу других объектов (с точки зрения JS можно сказать, что он содержит массив других объектов – как вы помните, в JS обращение к объекту всегда выполняется по ссылке). 

Так вот, если рассматривать эту структуру – объект и массив ссылок, то сам объект считается родителем (или предком), а те объекты, ссылки на которые он содержит – детьми (или потомками). Один и тот же объект может быть одновременно и предком (если он ссылается на кого-либо), и потомком (если на него кто-то ссылается). 

Также возможны варианты, когда объект не имеет предков – этим свойством обладает только корневой элемент – и когда объект не имеет потомков – тогда такой объект называется терминальным (или конечным). 

Еще одно важное условие – все объекты (кроме корневого) имеют только одного предка.  

В том случае, когда структура удовлетворяет этим условиям, она представляет собой дерево. 

Если вы посмотрите на структуру HTML документа, то увидите что эта структура удовлетворяет описанным свойством. 

Все теги являются вложенными в другие теги, кроме тега HTML, и, кроме этого, разместить тег внутри двух и более тегов одновременно попросту невозможно. 

Доступ к элементам.

Как уже говорилось, для обхода дерева можно применить обход дерева, и, кроме этого, функции для поиска определенных узлов. Рассмотрим оба варианта. 

Первый вариант – требует для работы наличие уже известного узла. Этим узлом обычно служит document.documentElement, но кроме него в большинстве браузеров можно использовать, например, document.body (для доступа непосредственно к содержимому тега <body>), а также списки элементов, например document.forms (все формы содержащиеся в документе) или document.images (все картинки документа).

Любой элемент имеет следующие ссылки на другие элементы: 

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

Например, в случае такого кода: 

<div id="element_01">someText</div>
<div id="element_02">Another text</div> 

если у нас существует переменная el, которая ссылается на div с id равным element_01, то, например, для браузера Firefox (и вообще всех браузеров на основе движка Gecko) указатель el.nextSibling будет указывать не на следующий div, как вы могли бы ожидать, а на пустой текстовый элемент (да, для текстовых элементов тоже создаются отдельные узлы).

Все дело в том, что пустое пространство между закрывающим тегом одного div-а и открывающим тегом другого тоже преобразуется в текстовый узел (правда, пустой).

Это нужно учитывать при использовании ссылок на следующие и предыдущие элементы, а также на потомков. 

При этом, в браузере Internet Explorer такое поведение наблюдаться скорее всего не будет. 

Это еще один пример различия браузеров – в данном случае говорят о различиях DOM модели разных браузеров, и эти различия не заканчиваются на построении дерева документов. 

Второй способ доступа к элементам, о котором я говорил – это использование функций поиска элемента. 

Таких функций три, но полноценно реализованы во всех браузерах только две: 

element.getElementById() (внимание -- «d» маленькая) и element.getElementByTagName()

Эти функции, как следует из их названия, позволяют получить элемент(ы) по ID или по названию тэга. 

При этом в браузерах Internet Explorer и Operа кроме поиска по ID также выполняется поиск по атрибуту name. 

Поскольку эти функции определены не для всего документа, а для каждого элемента, то, соответственно, поиск элементов выполняется среди потомков того элемента, для которого функция вызывается. 

Итак, мы уже умеем находить любой элемент DOM-дерева. Теперь настало время научиться работать с этими элементами. 

Тут все просто, хотя есть и свои подводные камни – об одном из них я напишу подробно. 

Элемент DOM-дерева имеет множество других свойств, кроме ссылок на предков и потомков. Например, можно изменять стили элемента (при помощи обращения к свойству style этого элемента), а также получать и изменять атрибуты элементов. 

Но в первую очередь нужно разобраться, как вообще можно управлять этими элементами – то есть, внести динамику в наш HTML на базовом уровне. 

Для того чтобы создавать элементы, существует (не удивляйтесь) два способа.  

Первый из них – это непосредственное изменение содержимого элементов. 

Для того чтобы изменить «внутренности» любого элемента, да и вообще для доступа к этим внутренностям, используется свойство element.innerHTML. Оно содержит весь текст, который расположен между открывающим и закрывающим тегами соответствующего элемента. При изменении этого свойства содержимое элемента тоже изменится (что незамедлительно будет показано браузером).

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

В то же время, данный способ не всегда удобен – например, для добавления элемента в список пришлось бы вручную изменять содержимое (и при этом учитывать имеющуюся структуру документа), а это бывает достаточно сложно. Кроме того, этот метод достаточно низкоуровневый – никто не гарантирует, что вы не сломаете полностью дерево HTML документа. Но в простых случаях этот способ – идеальное решение, тем более что работает он очень быстро. 

Вот как, например, можно заменить содержимое div-а из предыдущего примера:

el.innerHTML = "<p>Здесь будет новый текст</p>"; 

После выполнения этого кода div с ID равным element_01 будет содержать параграф, внутри которого будет содержаться текст «Здесь будет новый текст». При этом изменении также изменится и структура DOM-дерева – упомянутый div будет содержать не текстовый узел, а параграф, который в свою очередь уже и будет содержать текст.

Второй способ управления узлами – это использование функций element.createElement(), element.createTextNode(), element.appendChild(), element.insertBefore(), а также element.cloneNode(), element.replaceChild() и element.removeChild().

Функция createElement() ожидает на входе название тега элемента, который нужно создать. Созданный тег будет пустым. Если же нужно создать текстовый элемент, то нужно использовать функцию createTextNode(), и передать ей на вход текст – содержимое текстового элемента.

После создания элемента при помощи этих функций их можно разместить внутри дерева документа при помощи appendChild() -- в этом случае элемент будет вставлен после последнего потомка (или первым, если потомков нет) – или при помощи insertBefore() – в этом случае нужно также указать, перед каким элементом нужно вставить созданный.

Если же использовать replaceChild(), то новый элемент заменит указанный.

Также можно «скопировать» существующий элемент (вместо того чтобы его создавать) – в этом случае можно указать, копировать ли элемент полностью со всеми потомками, или только сам элемент (потомков у него не будет). 

Стоит заметить, что при перемещении элемента его потомки никуда не исчезают, а следуют за элементом. 

А теперь немного о подводных камнях. Дело в том, что кроме создания пустых текстовых элементов браузер также создает теги, которые многие программисты забывают прописать внутри HTML кода. Самая распространенная ошибка – это добавление строки в таблицу. 

Дело в том, что любая таблица содержит в себе tbody (то есть тело таблицы), и строки должны добавляться именно к этому элементу, а не к самой таблице. При попытке добавить строку (то есть – tr) непосредственно к элементу таблицы ничего не происходит.

Кроме описанных мной методов существуют также специальные методы – например, для работы с таблицами (то есть специальные методы для создания строк и элементов таблицы), но они особо не отличаются от методов для работы с HTML-элементами, а их применение только вносит некоторую путаницу. 

Какой из методов лучше использовать (или оба сразу), решать вам. В сети не угасают споры, что лучше, быстрее и правильнее – я же посоветую прислушиваться только к вашему здравому смыслу и смотреть по обстоятельствам. 



В начало страницы



В начало страницы