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, а затем
откройте его в броузере.
Посмотрите, что произойдет, если нажать на кнопку несколько раз. Объясните
результат.