Объектная модель документа (DOM)
Когда браузер подгружает и обрабатывает HTML документ, он создает объектную модель документа (DOM). DOM – это модель, в которой для представления каждого элемента в документе используются объекты JavaScript, а DOM – это механизм, благодаря которому вы можете программно заниматься содержанием HTML документа.
Примечание
В принципе, DOM может работать с любым языком программирования, который поддерживает браузер. Но на практике JavaScript доминирует в большинстве основных браузеров. И поэтому я не буду разграничивать DOM как абстрактную идею и DOM как коллекцию соответствующих объектов JavaScript.
Одной из причин, почему вам стоит обращать внимание на связи между элементами, которые я описал в предыдущих разделах, является то, что они сохраняются в DOM. И как следствие, вы можете использовать JavaScript, чтобы пройтись по древу элементов и изучить природу и структуру представленного документа.
Заметка
Использование DOM подразумевает использование JavaScript. Если вам надо освежить в памяти основы языка JavaScript, смотрите главу 4.
В этой части главы я покажу некоторые базовые характеристики DOM. Далее в книге я буду использовать jQuery для работы с DOM. В этом же разделе я покажу вам некоторые встроенные функции, в частности для того, чтобы потом наглядно показать, насколько элегантнее с этим справляется jQuery.
Использование DOM
Объект JavaScript, определяющий базовый функционал, доступный в DOM для всех типов элементов, называется HTMLElement
. Объект HTMLElement
определяет свойства и методы, общие для всех типов HTML элементов, включая свойства, показанные в таблице 2-3.
Таблица 2-3: Основные свойства HTMLElement
Свойство | Описание | Возвращает |
className |
получает или определяет список классов, к которым принадлежит элемент | string |
id |
получает или определяет значение атрибута id |
string |
lang |
получает или определяет значение атрибута lang |
string |
tagName |
возвращаем имя тега (указывая на тип элемента) | string |
Есть много различных свойств. Их точное число зависит от того, с какой версией HTML вы работаете, а этих четырех мне достаточно, чтобы показать базовые функции DOM.
DOM использует объекты, полученные из HTMLElement
, чтобы представить уникальные характеристики каждого типа элементов. Например, объект HTMLImageElement
используется в DOM для представления элемента img
. И этот объект определяет свойство src
, которое соответствует атрибуту src
элемента img
. Я сейчас не буду вдаваться в детали по всем объектам, определяющим конкретные элементы, но вы без сомнения можете работать со свойствами, соотносящимися к атрибутам элементов.
Вы можете получить доступ к DOM, используя глобальную переменную document, которая возвращает объект Document
. Объект Document
представляет HTML документ, который отображается в браузере, и определяет некоторые методы, которые позволят вам находить объекты в DOM, как описано в таблице 2-4.
Таблица 2-4: Методы объекта Document для нахождения элементов
Свойство | Описание | Возвращает |
getElementById(<id>) |
возвращает элемент с конкретным значением id |
HTMLElement |
getElementsByClassName(<class>) |
возвращает элементы с конкретным значением class |
HTMLElement[] |
getElementsByTagName(<tag>) |
возвращает элементы конкретного типа | HTMLElement[] |
querySelector(<selector>) |
возвращает элемент, который соответствует конкретному селектору CSS | HTMLElement |
querySelectorAll(<selector>) |
возвращает все элементы, которые соответствует конкретному селектору CSS | HTMLElement[] |
Еще раз повторю, что я выбрал лишь те методы, которые будут полезны для данной книги. Последние два метода, описанные в таблице, используют CSS селекторы, о которых я расскажу в главе 3. В листинге 2-15 показано, как в документе можно использовать объект Document
для поиска элементов конкретного типа.
Листинг 2-15: Поиск элементов в DOM
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
h1
{
width: 700px;
border: thick double black;
margin-left: auto;
margin-right: auto;
text-align: center;
font-size: x-large;
padding: .5em;
color: darkgreen;
background-image: url("border.png");
background-size: contain;
margin-top: 0;
}
.dtable
{
display: table;
}
.drow
{
display: table-row;
}
.dcell
{
display: table-cell;
padding: 10px;
}
.dcell > *
{
vertical-align: middle;
}
input
{
width: 2em;
text-align: right;
border: thin solid black;
padding: 2px;
}
label
{
width: 5em;
padding-left: .5em;
display: inline-block;
}
#buttonDiv
{
text-align: center;
}
#oblock
{
display: block;
margin-left: auto;
margin-right: auto;
width: 700px;
}
</style>
</head>
<body>
<h1>Jacqui"s Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div class="drow">
<div class="dcell">
<img src="astor.png" /><label for="astor">Astor:</label>
<input name="astor" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png" /><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required>
</div>
<div class="dcell">
<img src="rose.png" /><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div class="drow">
<div class="dcell">
<img src="peony.png" /><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png" /><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png" /><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
<script>
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
console.log("Element: " + elements[i].tagName + " " + elements[i].src);
}
</script>
</body>
</html>
В этом примере я разместил элемент script
в самом конце элемента body
. Когда браузеры находят в документе script
, они сразу же начинают выполнять выражения JavaScript, до того, как успеет загрузиться и будет обработана оставшаяся часть документа. Это может создать проблему, если вы работаете с DOM, это обозначает, что поиск элементов с использованием объекта Document
осуществляется до того, как интересующие вас объекты были созданы и обработаны в DOM. Чтобы избежать этого, я разместил элемент script
в самом конце документа. jQuery довольно изящно справляется с этой задачей, о чем я расскажу в главе 5.
В скрипте я использовал метод getElementsByTagName
, чтобы найти в документе все элементы img
. Этот метод возвращает массив объектов, которые я перечисляю и вывожу на консоль значения свойств tagName
и src
для каждого объекта. На консоли виден следующий результат:
Element: IMG http://www.jacquisflowershop.com/jquery/astor.png
Element: IMG http://www.jacquisflowershop.com/jquery/daffodil.png
Element: IMG http://www.jacquisflowershop.com/jquery/rose.png
Element: IMG http://www.jacquisflowershop.com/jquery/peony.png
Element: IMG http://www.jacquisflowershop.com/jquery/primula.png
Element: IMG http://www.jacquisflowershop.com/jquery/snowdrop.png
Изменение объектов в DOM
Объекты в DOM живые. Это обозначает, что изменения свойств объекта в DOM повлияют на вид документа в браузере. Листинг 2-16 показывает скрипт, который совершает данную операцию. (Чтобы избежать дублирования, тут показан только элемент script
. Остальная часть документа точно такая же, как и в последнем примере).
Листинг 2-16: Изменение свойств DOM объектов
...
<script>
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
elements[i].src = "snowdrop.png";
}
</script>
...
В этом скрипте я изменил значение атрибута src
на snowdrop.png
для всех элементов img
. Что из этого получилось, видно на рисунке 2-6.
Рисунок 2-6: Использование DOM для изменения HTML документа

Изменение стилей
DOM также можно использовать для изменения свойств CSS. (Вспомнить CSS вам поможет глава 3). Поддержка DOM API довольно обширна для CSS, но самый простой путь изменить CSS – это использовать свойства style
объекта HTMLElement
. Объект, возвращаемый свойством style
, определяет свойства, которые соответствуют свойствам CSS. (Прошу прощения за обилие свойств в данном предложении).
Способы наименования свойств в CSS и для объектов, которые возвращает style
, немного различаются. Например, свойство CSS background-color
становится свойством style.backgroundColor
объекта. В листинге 2-17 показано, как использовать DOM для управления стилями.
Листинг 2-17: Использование DOM для изменения стиля элементов
...
<script>
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
if (i > 0) {
elements[i].style.opacity = 0.5;
}
}
</script>
...
Этим скриптом я изменил значение свойства opacity
для всех элементов img
, кроме первого. Я оставил один элемент нетронутым, чтобы вы увидели разницу. Это видно на рисунке 2-7.
Рисунок 2-7: Использование JavaScript для изменения свойств CSS

Обработка событий
События – это сигнал, посылаемый браузером для определения изменения в статусе одного или более элементов в DOM. Есть различные события, определяющие разные изменения статуса. Например, событие click
срабатывает тогда, когда пользователь щелкает мышкой по элементу в документе, а событие submit
срабатывает тогда, когда пользователь отправляет форму. Многие события связаны между собой. Например, событие mouseover
срабатывает тогда, когда пользователь водит курсором мышки поверх элемента, а событие mouseout
срабатывает тогда, когда пользователь выводит мышку из зоны элемента.
Можно реагировать на события, связывая функцию JavaScript с событием для элемента DOM. В листинге 2-18 показан пример этого.
Листинг 2-18: Обработка события
...
<script>
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
elements[i].onmouseover = handleMouseOver;
elements[i].onmouseout = handleMouseOut;
}
function handleMouseOver(e) {
e.target.style.opacity = 0.5;
}
function handleMouseOut(e) {
e.target.style.opacity = 1;
}
</script>
...
Этот скрипт определяет две функции обработчика, которые я назначаю значениями свойств onmouseover
и onmouseout
для DOM-объектов img
. Действие этого скрипта заключается в том, что рисунки становятся частично прозрачными, если по ним двигается курсор мышки, и становятся нормального цвета, когда курсор выходит за область рисунка. Я не намереваюсь слишком пристально рассматривать механизм обработки событий DOM API, поскольку в главе 9 будет рассмотрена обработка событий в jQuery. И все же я хочу обратить внимание на объект, которому передаются функции обработки событий, – это объект Event
. В таблице 2-5 показаны наиболее важные члены объекта Event
.
Таблица 2-5: Функции и свойства объекта Event
Имя | Описание | Возвращает |
type |
Название события, например mouseover . |
string |
target |
Элемент, на который это событие направлено. | HTMLElement |
currentTarget |
Элемент, слушатели которого вызваны в настоящее время. | HTMLElement |
eventPhase |
Фаза жизненного цикла события. | number |
bubbles |
Возвращает true, если событие будет "пузыриться" по документу; и false , если нет. |
boolean |
cancelable |
Возвращает true, если событию установлено действие по умолчанию, которое можно отменить; в противном случае возвращает false. |
boolean |
stopPropagation() |
Останавливает поток событий по дереву элементов, после того как сработали слушатели события для данного элемента. | void |
stopImmediatePropagation() |
Незамедлительно останавливает поток событий по дереву элементов. Незадействованные событийные слушатели для текущего элемента игнорируются. | void |
preventDefault() |
Запрещает браузеру совершать действие по умолчанию, связанное с событием. | void |
defaultPrevented |
Возвращает true, если вызывалась функция preventDefault(). |
boolean |
В предыдущем примере я использовал свойство target, чтобы найти элемент, для которого сработало событие. Некоторые из других функций, методов и свойств относятся к потоку событий и действиям по умолчанию, о чем я кратко расскажу в следующем разделе. В этой главе я хочу всего лишь заложить фундамент для дальнейшего прочтения книги.
Поток событий
Событие имеет три фазы жизненного цикла: фаза перехвата (capture), нахождение целевого элемента (target), фаза всплывания (bubbling). Когда срабатывает триггер, браузер определяет элемент, к которому относится данное событие, эта фаза называется фаза перехвата. Браузер идентифицирует все элементы между элементом body и целевым элементом, и проверяет каждый из них, чтобы посмотреть, есть ли у них обработчики, которые должны получить информацию о событиях, происходящих в их узлах-потомках. Браузер запускает любой такой обработчик, прежде чем запустить обработчик для целевого элемента. (Я покажу вам, как "запрашивать информацию" о событиях узлов-потомков в главе 9.)
После завершения фазы перехвата начинается фаза нахождения целевого элемента, самая простая из трех. После окончания фазы перехвата браузер активирует все обработчики того типа событий, которые назначены для целевого элемента.
После завершения фазы нахождения целевого элемента, браузер начинает его обработку, двигаясь по цепочке элементов-предков обратно к элементу body. Для каждого элемента браузер делает проверку, есть ли такие обработчики для данного события, которые не были включены в фазу перехвата (об это я подробнее расскажу в главе 9). Не все события поддерживают пузырьковый эффект (баблинг). Чтобы проверить это, вы можете использовать свойство bubbles
. Значение true
оказывает, что баблинг имеет место быть, а false
, что нет.
Действия по умолчанию
Некоторые события определяют действие по умолчанию, которое будет выполнено после запуска события. Например, действием по умолчанию для события click
будет таковым, что браузер будет загружать документ с тем URL, который определен в атрибуте href
. Если для события определено действие по умолчанию, значение его свойства cancelable
будет true
. Исполняемое действие по умолчанию можно остановить, вызвав метод preventDefault
. Запомните, что вызов функции preventDefault
не остановит действие на фазе перехвата, фазе нахождения целевого элемента и фазе всплывания. Эти фазы будут пройдены, но браузер не будет выполнять действие по умолчанию в конце фазы всплывания (баблинга). Вы можете посмотреть, была ли вызвана функция preventDefault
более ранним обработчиком, используя свойство defaultPrevented
. Если возвращается true
, значит, функция preventDefault
была вызвана.