Объектная модель документа

DOM (Document Object Model, объектная модель документа) - представление частей веб-страницы (окна, элементов, стилей) в виде иерархической системы объектов. Отношение иерархии не всегда оказывается достаточно очевидным, т.к. между частями иногда существуют довольно сложные отношения, например, в случае фреймов или открытия одного окна из другого. Каждый объект представляет собой совокупность трех компонентов:
• свойства (встроенные переменные);
• методы (встроенные функции);
• события (ситуации с программируемой обработкой).
Одним из наиболее очевидных применений DOM является разработка интерактивных веб-страниц.

Структура документа в DOM

DOM представляет документ как иерархию объектов нового типа - узлов (node). На вершине иерархии находится узел (объект) document, который представляет весь документ. В качестве узлов в DOM представлено все содержание документа: HTML элементы, атрибуты этих элементов и текст HTML элементов-контейнеров. Возьмем для примера небольшой фрагмент HTML документа:
<HTML>
<HEAD>
<TITLE>Структура DOM</TITLE>
</HEAD>
<BODY>
<H1>Иерархия узлов</H1>
<P>На вершине иерархии находится узел<TT>document</TT>, который представляет в DOM сам документ.</P>
</BODY>
</HTML>

Раздел <HEAD> этого документа содержит элемент <TITLE> с текстом. Раздел <BODY> содержит заголовок первого уровня и параграф, в котором одно слово набрано телетайпным шрифтом. На следующей диаграмме (рис.1) показаны все узлы этого документа, а на рис.2 результат выполнения этого кода в браузере. Узлы типа элемент изображены в виде тэгов этого элемента и размещены в прямоугольных ячейках. Узлы типа текст (их содержание сокращено для компактности) размещены в ячейках с закругленными углами. Линии соединяют родительский узел с расположенными под ним его потомками.



Рис.1


Рис.2


Сравнивая эту диаграмму с ее HTML источником, можно легко понять, что иерархия узлов задается вложенностью тэгов друг в друга и текста внутрь элементов. Текст элемента <P> представлен двумя текстовыми узлами, поскольку он разбит на две части элементом <TT>. Показанную на рисунке иерархию узлов принято называть деревом документа. Надо отметить, что Internet Explorer 5 не считает корневой узел document частью этого дерева.
Очевидно, что элементы, имеющие открывающий и закрывающий тэги (элементы-контейнеры), могут иметь потомков. Текст, атрибуты и элементы типа <IMG>, не имеющие закрывающего тэга, иметь потомков не могут. Очевидно также, что узлы типа атрибут могут быть потомками только узлов типа элемент. В HTML разные элементы, например, <P> или <IMG>, имеют разный набор допустимых для них атрибутов. В DOM узлы-элементы разного вида также имеют разный набор допустимых для них узлов-атрибутов, зависящих от реализации браузеров.

Узлы разного типа (document, элементы, атрибуты и текст) имеют свой набор свойств и методов, которые позволяют через сценарии манипулировать ими. Ключевые свойства и методы узлов описаны в данной лабораторной работе. Ряд узлов-элементов (объектов) имеют свои собственные свойства и методы. Так, например, объект элемента <TABLE> имеет метод createTHead(). При обсуждении свойств и методов узлов мы будем использовать следующий фрагмент документа:
<DIV>
<UL ID="components">
<LI>HTML</LI>
<LI>CSS</LI>
<LI>Javascript</LI>
</UL>
</DIV>

Вид страницы, содержащей данный код приведен ниже (рис. 3):


Рис.3

В DOM этому фрагменту соответствует ветка дерева, растущая из узла <DIV> к узлу <UL>. Здесь она разветвляется на три веточки по числу узлов <LI> (узлы-атрибуты не принято включать в состав дерева). Каждый из этих узлов имеет по одному побегу, который заканчивается текстовым узлом.

Навигация по дереву документа  

        Навигацию по дереву документа можно начинать с любого узла-элемента, для которого мы знаем идентификатор, присваиваемый ему в качестве значения атрибута ID. Ссылку на такой узел можно получить с помощью метода getElementById() объекта document. Параметром метода является идентификатор. Следующая строка кода присваивает переменной oList ссылку на наш список:
var oList = document.getElementById("components")
Стартуя с некоторого узла, мы можем бродить по дереву в любом направлении, используя ряд свойств узлов. Так, узлы-элементы и текстовые узлы имеют свойство parentNode, которое возвращает ссылку на родительский узел. Возьмем для примера узел (объект) oList. Ссылку на родительский элемент <DIV> этого узла можно получить следующий образом:
var oParent = oList.parentNode
Узлы-элементы и текстовые узлы, являющиеся потомками некоторого узла, входят в состав коллекции childNodes этого узла. (Узлы-атрибуты составляют отдельную коллекцию attributes, которая обсуждается в последнем разделе статьи.) К каждому из них можно обращаться по индексу массива. Например, строка кода
var oItem1 = oList.childNodes[1]
присваивает переменной oItem1 ссылку на элемент <LI>CSS</LI> нашего списка. Именно этот элемент представлен в DOM как узел childNodes[1] узла oList. Первый (childNodes[0]) и последний элементы коллекции имеют специальные имена: firstChild и lastChild. Эти имена являются свойствами родительского узла. Каждый из элементов коллекции имеет свойства previousSibling и nextSibling. Эти свойства хранят ссылку на ближайших братьев элемента - предыдущий и последующий элементы коллекции (возвращают null, когда братьев нет). Так, элемент childNodes[1] является свойством nextSibling элемента childNodes[0] и свойством previousSibling элемента childNodes[2]. Используя эти свойства, мы можем получить ссылку на узел childNodes[1] любым из следующих способов:
* oList.firstChild.nextSiblingoList
* oList.childNodes[2].previousSibling
Ссылка на более удаленные узлы, как по горизонтали, так и по вертикали дерева формируется путем слияния ссылок на ближайших родственников по стандартным правилам объектно-ориентированного программирования. Так, oList.childNodes[1].firstChild является ссылкой на текст"CSS"элемента <LI>CSS</LI> нашего списка.
На следующей диаграмме (рис.4) приведены имена всех ближайших родственников некоторого узла oNode.  


Рис.4

Заметим, что все описанные выше свойства узлов (parentNode, firstChild, lastChild, nextSibling и previousSibling), необходимые для навигации по дереву документа, являются свойствами только для чтения. Помимо них, узлы имеют еще ряд свойств, которые мы сейчас опишем.

Свойства-характеристики узлов

Свойство узла nodeType (только для чтения) возвращает 1, 2 или 3 для узлов, соответствующих тэгу, атрибуту или тексту, соответственно. Свойство nodeName (только для чтения) возвращает имя HTML тэга, которому соответствует данный узел, например, <P> для параграфа или <UL> для ненумерованного списка. Для узлов-атрибутов nodeName возвращает название атрибута, а для тестовых узлов возвращает #text.
Текстовые узлы имеют еще одно очень важное свойство: nodeValue. Это свойство для чтения и записи хранит содержание текстового узла. Для элементов оно возвращает null, а для атрибутов - значение атрибута.  

 Создание новых узлов

* метод createElement()
* метод createTextNode()
Технику создания новых элементов обсудим на конкретном примере. Мы хотим добавить к нашему списку элемент
<LI>XML</LI>
Этому HTML элементу в DOM соответствуют два узла: узел-элемент <LI> и текстовый узел"XML". Следовательно, мы должны создать два новых узла. Новые узлы создаются с помощью методов createElement() и createTextNode() объекта document.
Метод createElement()
Метод createElement() принимает в качестве параметра строку с названием тэга элемента и создает новый HTML элемент указанного типа. Например, строка кода
var oItem = document.createElement("LI")
создает новый элемент списка <LI>, у которого нет содержания. Метод возвращает ссылку на созданный им объект. Созданный выше элемент <LI> находится в памяти, но не входит в состав текущего документа. Для того чтобы он стал частью документа, его надо добавить к существующим узлам документа с помощью методов insertBefore() или appendChild(), которые подробно описаны ниже.
Хотя название тэга элемента можно набирать как заглавными, так и прописными буквами, рекомендуется использовать ЗАГЛАВНЫЕ БУКВЫ.
Заметим, что в Internet Explorer 5 можно создавать через сценарий все элементы, кроме <FRAME>, <IFRAME> и <SELECT>. Свойства создаваемых элементов являются свойствами для чтения и записи.
Метод createTextNode()
Метод createTextNode() используется для создания текстового узла. Он принимает в качестве параметра строку текста, которая задает значение свойства nodeValue текстового узла. Например, строка кода
var oText = document.createTextNode("XML")
создает новый текстовый узел"XML". Метод возвращает ссылку на созданный им объект. Созданный текст еще не входит в состав текущего документа. Для того чтобы он стал частью документа, его надо присоединить к существующим узлам документа с помощью методов appendChild(), replaceNode() или insertBefore(), которые подробно описаны ниже.
Если у вас случайно оказалась ссылка на ненужный текстовый узел (например, oText), то можно не создавать нового узла, а воспользоваться уже существующим. Для этого надо просто присвоить новый текст в качестве значения свойства nodeValue существующего узла:
oText.nodeValue= "XML"
Итак, мы создали два новых узла: узел-элемент <LI> и текстовый узел"XML". Теперь займемся встраиванием этих узлов в документ.

Редактирование дерева документа.

Рассмотрим несколько методов, с помощью которых можно изменять содержимое Web-страницы:
* вставка: метод appendChild()
* замещение: метод replaceChild()
* удаление: метод removeChild()
DOM, как редактор, позволяет копировать, вставлять, замещать и удалять как отдельные узлы, так и целые ветви дерева документа. Мы рассмотрим добавление, замещение и удаление узлов и начнем с присоединения одного узла к другому.
Напомню, что у нас есть два узла: узел-элемент <LI> и текстовый узел"XML". Оба узла находятся в памяти, и мы хотим встроить их в текущий документ. Прежде всего, надо задать текст "XML" в качестве содержания элемента <LI>. Сделать это можно с помощью метода appendChild().
Вставка: метод appendChild()
Этот метод добавляет элемент в конец коллекции childNodes узла, который его активизировал. Сам этот узел становится родительским узлом для узла, ссылку на который метод принимает в качестве параметра. Например, строка кода
oItem.appendChild(oText)
добавляет узел oText к узлу oItem. Отметим, что метод возвращает ссылку на объект, который он добавляет. В нашем случае это объект oItem.firstChild. Теперь мы имеет в памяти элемент (веточку дерева из двух узлов)
<LI>XML</LI>
Пора вставлять эту веточку в текущий документ. Если мы хотим вставить ее в самый конец нашего списка, то надо, как и выше, использовать метод appendChild(): oList.appendChild(oItem)
Поскольку узел oList, к которому мы присоединили узел oItem, является частью текущего документа, созданный нами элемент списка также становится частью документа. Теперь наш список выглядит так:
<UL ID="components">
<LI>HTML</LI>
<LI>CSS</LI>
<LI>Javascript</LI>
<LI>XML</LI>
</UL>

Таким образом, код нашей странички будет выглядеть так:
<HTML>
<HEAD>
<TITLE> Добавление элемента в конец списка </TITLE>
<script language="JavaScript"><!--
function newstr(obj)
{var oList = document.getElementById("components")
var oItem = document.createElement("LI")
var oText = document.createTextNode("XML - новая строка")
oItem.appendChild(oText)
oList.appendChild(oItem)
}
--></script>
</HEAD>
<BODY>
<DIV>
<UL ID="components">
<LI> HTML </LI>
<LI> CSS </LI>
<LI> Javascript </LI>
</UL>
</DIV>
<form name="form1">
<input type="button" value="Добавить строку в конец списка" onClick="newstr(form1)">
</form>
</BODY>
</HTML>

В результате получится окно, изображенное на рис.5:  


Рис. 5

Задание. Попробуйте набрать в текстовом редакторе "Блокнот" код этой странички. Сохраните получившийся файл под именем dom1.html, а затем откройте его в броузере. Посмотрите, что произойдет с содержимым страницы, если нажать на кнопку. Объясните получившийся результат.
 

Замещение: метод replaceChild(). Метод replaceChild() позволяет у узла, который его активизирует, заменить одного из его потомков новым. Ссылку на новый и на заменяемый узлы метод принимает в качестве первого и второго параметров, соответственно. Так, следующий фрагмент сценария
var oItem = document.createElement("LI")oItem.appendChild(document.createTextNode("JScript"))oList.replaceChild(oItem, oList.lastChild)
создает сначала элемент списка с текстом "JScript", а затем заменяет им последний элемент нашего списка. Отметим, что метод возвращает ссылку на вставленный в документ узел.
Теперь наш список выглядит так:
<UL ID="components">
<LI>HTML</LI>
<LI>CSS</LI>
<LI>JScript</LI>
</UL>

Код данной страницы:
<HTML>
<HEAD>
<TITLE> Замена элемента списка </TITLE>
<script language="JavaScript"><!--
function repstr(obj)
{var oList = document.getElementById("components")
var oItem = document.createElement("LI");oItem.appendChild(document.createTextNode("JScript"));oList.replaceChild(oItem, oList.lastChild)
}
--></script>
</HEAD>
<BODY>
<DIV>
<UL ID="components">
<LI> HTML </LI>
<LI> CSS </LI>
<LI> Javascript </LI>
</UL>
</DIV>
<form name="form1">
<input type="button" value="Замена последнего элемента списка" onClick="repstr(form1)">
</form>
</BODY>
</HTML>

В результате получится окно, изображенное на рис.6:  


Рис.6

Задание. Попробуйте набрать в текстовом редакторе "Блокнот" код этой странички. Сохраните получившийся файл под именем dom2.html, а затем откройте его в броузере. Посмотрите, что произойдет, если нажать на кнопку. Объясните полученный результат.
 

Удаление: метод removeChild().
Метод removeChild() позволяет у узла, который его активизирует, удалить одного из его деток. Ссылку на удаляемый узел метод принимает в качестве параметра. Например, строка кода
var oRemovedItem = oList.removeChild(oList.lastChild)
удаляет из нашего списка последний элемент. Метод возвращает ссылку на удаляемый им узел. Поскольку удаленный из документа узел остается в памяти, мы можем в дальнейшем работать с ним, используя эту ссылку, например, пристроить в какой-нибудь другой список.
<HTML>
<HEAD>
<TITLE> Удаление последнего элемента списка </TITLE>
<script language="JavaScript"><!--
function delstr(obj)
{var oList = document.getElementById("components")
var oRemovedItem = oList.removeChild(oList.lastChild)
}
--></script>
</HEAD>
<BODY>
<DIV>
<UL ID="components">
<LI> HTML </LI>
<LI> CSS </LI>
<LI> Javascript </LI>
</UL>
</DIV>
<form name="form1">
<input type="button" value="Удалить последний элемент списка" onClick="delstr(form1)">
</form>
</BODY>
</HTML>

В результате получится окно, изображенное на рис.7:  


Рис.7

Задание. Попробуйте набрать в текстовом редакторе "Блокнот" код этой странички. Сохраните получившийся файл под именем dom3.html, а затем откройте его в броузере. Посмотрите, что произойдет, если нажать на кнопку несколько раз. Объясните результат.
 

Тест по DOM

В начало

Hosted by uCoz