Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Ajax в действии

.pdf
Скачиваний:
92
Добавлен:
01.05.2014
Размер:
6.34 Mб
Скачать

Глава 2. Знакомство с Ajax 75

Листинг 2.2. Содержимое файла window.сss

div.window{ position: absolute; overflow: auto;

background-color: feeefff; border: solid #0066aa 2px; margin: 8px;

padding: Opx;

/* 1 Размеры элемента */ width: 42Opx;

height: 280px;

}

div.titlebar{

/* 2 Текстура фона */ background-color: #0066aa; background-image: url(images/titlebar_bg.png); background-repeat: repeat-x; color:white;

border-bottom: solid black lpx; width: 100%;

height: 16px; overflow:hidden;

}

span.titleButton{ position: relative; height: 16px; width: 16px; padding: Opx;

margin: Opx lpx; Opx lpx; /* 3 Выравнивание */ float:right;

}

span.titleButtonfmin{ background: transparent

url(images/min.png) top left no-repeat;

}

span.titleButton#max{ background: transparent

url(images/max.png) top left no-repeat;

}

span.titleButton#close{ background: transparent

url(images/close.png) top left no-repeat;

}

div.contents { background-color: #e0e4e8; overflow: auto;

padding: 2px; height:240px;

}

div.item{

position : relative; height : 64px; width: 56px;

float: left;

Часть I. Новый взгляд на Web-приложение

color : #004488; font-size: 18; padding: Орх; margin: 4px;

}

div.item div.itemName {

/* 4 Позиционирование текста */ margin-top: 48рх;

font: 10px verdana, arial, helvetica; text-align: center;

}

div.folder{

background: transparent url(images/folder.png) top left no-repeat;

}

div.file{

background: transparent

url(images/file.png) top lef t no-repeat;

}

div.special{

background: transparent url(images/folder_important.png) top lef t no-repeat;

Мы уже рассмотрели ряд приемов, примененных в составе данных таблиц гилей и предназначенных для форматирования внешнего вида конкретных лементов. В листинге мы также отметили фрагменты, демонстрирующие озможности CSS: размещение на экране О, текстура ©, взаимное располосение элементов © и позиционирование текста относительно графики О.

CSS — важный элемент набора инструментальных средств для разработ- и Web-приложений. Как было показано выше, каскадные таблицы стилей южно применить не только для настройки внешнего вида отдельных Webграниц, но и для формирования пользовательского интерфейса, что имеет олыное значение при разработке Ajax-приложений.

\Л. Организация просмотра с помощью РОМ

ЮМ (Document Object Model) представляет документ (Web-страницу) роцессору JavaScript. Благодаря DOM появляется возможность управять структурой документа (рис. 2.3) из программы. Такая возможность райне важна для разработчиков Ajax-приложений. В классическом Webриложении все содержимое окна браузера регулярно обновляется при поучении с сервера потока, содержащего HTML-данные. Подготавливая ноый вариант документа, можно существенно изменить интерфейс. В Ajaxриложении большая часть изменений интерфейса осуществляется с помощью DOM. HTML-элементы в составе Web-страницы составляют древовидую структуру. Корнем данного дерева является дескриптор HTML, который редставляет весь документ. В нем содержится элемент BODY, соответству-

Глава 2. Знакомство с Ajax

77

Рис. 2.3. HTML-документ представляется средствами DOM как древовидная структура, каждый элемент которой соответствует HTML-дескриптору

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

DOM-представление Web-страницы также имеет древовидную структуру, составленную из элементов, или узлов, которые содержат дочерние узлы, и т.д. Процессор JavaScript представляет корневой узел текущей Webстраницы посредством глобальной переменной document, которая выполняет роль стартовой точки для всех действий с DOM-данными. Структуру DOM определяет спецификация W3C. Для каждого элемента древовидной структуры существует один родительский элемент, любое, в том числе нулевое количество дочерних элементов, и любое количество атрибутов, хранящихся в ассоциативном массиве (т.е. массиве, для которого ключевым значением является не числовой индекс, а текст). На рис. 2.3 показана структура документа, код которого был представлен в листинге 2.2. Данная структура отображается с помощью инструмента Mozilla DOM Inspector (подробно он

78 Часть I. Новый взгляд на Web-приложение

рассмотрен в приложении А).

Взаимосвязь элементов DOM отражает структуру HTML-документа и является двухсторонней. Изменение структуры DOM влияет на HTMLразметку и, следовательно, на представление страницы.

Так выглядит DOM "на верхнем уровне". В следующем разделе вы увидите, как структура DOM представляется интерпретатору JavaScript, и узнаете, как выполнять с ней требуемые действия.

2.4.1 Обработка DOM с помощью JavaScript

В процессе работы пользователя с любым приложением возникает необходимость изменять интерфейс. Это надо, например, для того, чтобы обеспечить обратную связь с пользователем (он должен видеть реакцию на свои действия). Изменения могут потребоваться любые: замена текста статической метки или цвета одного из элементов, вывод диалогового окна и даже обновление значительной части окна и вывод нового набора компонентов. Чаще всего приходится создавать древовидную структуру DOM, предоставляя браузеру HTML-данные (другими словами, формировать Web-страницу).

Документ, который был показан в листинге 2.2 и на рис. 2.3, достаточно сложен. Мы же начнем обсуждение действий с DOM на простом примере. Предположим, что нам необходимо вывести приветствие пользователю. При первой загрузке страницы мы еще не знаем его имени, поэтому нам понадобится изменить структуру документа несколько позже, добавив имя пользователя. Воздействовать на узлы DOM, вероятнее всего, придется из программы. В листинге 2.3 показан HTML-код простой Web-страницы.

Листинг 2.3. Страница Ajax-приложения hello

<html>

<head>

< ! —

О Ссылка на

таблицы стилей —>

< l i n k r e l = ' s t y l e s h e e t '

t y p e = ' t e x t / e s s '

h r e f « • h e l l o . e s s 1

/>

 

< ! —

© Ссылка на

J a v a S c r i p t - с ц е н а р и й —>

< s c r i p t t y p e = ' t e x t / j a v a s c r i p t '

s r c = ' h e l l o . j s ' > < / s c r i p t >

</head>

 

 

<body>

 

 

<p i d = ' h e l l o ' > h e l l o < / p >

 

<! —

© Пустой элемент

—>

<div

i d = ' e m p t y ' x / d i v >

 

</body>

</html>

В документе содержатся ссылки на два внешних ресурса: каскадные таблицы стилей О и файл, содержащий JavaScript-код ©. Мы также определили пустой элемент div с идентификатором ©. С помощью программы мы можем 5ключить в его состав другие элементы.

Рассмотрим ресурсы, на которые ссылается документ. В CSS-файле определены простые стили, позволяющие выделять пункты списка и изменять

Глава 2. Знакомство с Аjах 79

шрифт и цвет. Содержимое CSS-файла приведено в листинге 2.4.

Листинг 2.4. Содержимое файла hello .css

.declared{ color: red;

font-family: arial; font-weight: normal; font-size: 16px;

}

.programmed! color: blue;

font-family: helvetica; font-weight: bold; font-size: lOpx;

Мы определили два стиля для исходных DOM-узлов. (Имена стилей могут быть произвольными. В данном случае мы выбрали их так, чтобы упростить восприятие примера, но с таким же успехом мы могли использовать имена fred и jim.) Ни один из этих стилей не используется в HTMLдоукменте, но они могут быть применены к элементам в результате выполнения программы. В листинге 2.5 показан JavaScript-код для страницы, представленной в листинге 2.4. Когда документ загружается, программа связывает стиль с существующим узлом и создает новые DOM-элементы.

Листинг 2.5. Содержимое файла h e l l o . j s

window.onload=function(){

// Получение элемента по идентификатору var hello=document.getElementById('hello') ; hello.className='declared' ;

var empty=document.getElementById('empty' ); addNode(empty,"reader of") ;

addNode(empty, "Ajax in Action!"); var children=empty.childNodes;

for (var i=0;i<children.length;i++){ children[i].className='programmed' ;

}

// Непосредственная установка стилей empty.style.border='solid green 2px'; empty.style.width="200px";

}

function addNode(el,text){ // Создание нового элемента

var childEl=document.createElement("div"); el.appendChild(childEl);

// Формирование текста

var txtNode=document.createTextNode(text); childEl.appendChild(txtNode);

80 Часть I. Новый взгляд на Web-приложение

Код JavaScript сложнее для восприятия, чем HTML-документ или стили. Точкой входа в данном случае является функция window.onload(), которая вызывается после загрузки всей страницы. К этому моменту древовидная структура DOM уже сформирована, и мы можем начинать работу с ней. В листинге 2.5 имеется несколько методов, предназначенных для модификации структуры DOM. В частности, с их помощью можно изменять атрибуты, скрывать и вновь отображать DOM-узлы и даже создавать в процессе выполнения программы новые узлы. Мы не будем останавливаться на каждом методе (подробную информацию о них вы сможете найти в источниках, ссылки на которые приведены в конце главы), а ограничимся рассмотрением в последующих разделах некоторых, используемых наиболее часто.

2.4.2. Поиск узла DOM

Первое, что надо сделать для того, чтобы изменить структуру DOM из JavaScript-программы, — найти элементы, которые следует модифицировать. Как было сказано ранее, в начале работы мы имеем лишь ссылку на корневой узел в глобальной переменной document. Все остальные узлы DOM являются дочерними (или более отдаленными потомками) document. Организовать пошаговый просмотр древовидной структуры большого документа — достаточно сложная задача. К счастью, ее можно упростить. Один из самых распространенных приемов — пометить элемент уникальным идентификатором. В функции onloadO, код которой показан в листинге 2.5, мы организуем поиск двух элементов: абзаца, стиль которого изменяем, и пустого элемента <div>, в состав которого включаем новые элементы. В открывающем дескрипторе каждого из этих элементов мы с помощью атрибута id задаем идентификатор.

<р i d = ' h e l l o ' >

и

<div id='empty1></div>

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

var hello=document.getElementById('hello') ;

Заметьте, что данный метод принадлежит объекту Document. В простых случаях, подобных рассматриваемому, молено ссылаться на текущий объект Document посредством переменной document. При использовании IFrame появляется несколько объектов Document, и приходится внимательно следить за тем, к какому из них осуществляется обращение.

В некоторых ситуациях необходимо организовать пошаговый обход дерева DOM. Поскольку узлы DOM организованы в виде древовидной структуры, каждый узел может иметь один родительский узел и любое число дочерних узлов. Доступ к ним осуществляется с помощью свойств parentNode и childNodes. Свойство parentNode ссылается на другой объект DOM, a childNodes — на JavaScript-массив узлов, которые приходится просматривать по очереди.

Глава 2. Знакомство с Ajax

81

var children=empty.childNodes;

for (var i=0;Kchildren . length;i++){

Если требуемый узел не помечен уникальным идентификатором, поиск его осуществляется по-другому: с помощью функции getElementsByTagName. Например, в результате вызова document.getElementsByTagName("UL") будет возвращен массив элементов UL, присутствующих в документе.

Последний способ применяется при работе с документом, структуру которого разработчик не может контролировать. Считается, что функция getElementByld дает более надежные результаты, чем getElementsByTagName (), поскольку при ее использовании не приходится учитывать структуру документа, которая может измениться.

2.4.3. Создание узла DOM

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

Вернемся к листингу 2.5. В начале работы узел с идентификатором empty пуст. Когда документ загружается, мы динамически формируем содержимое этого узла. В функции addNode () вызываются стандартные методы document .createElement() и document.createTextNode(). Метод createElement (), которому в качестве параметра передается тип дескриптора, создает HTML-элемент.

var childEl=document.createElement("div") ;

Метод createTextNode () формирует DOM-узел, представляющий фрагмент текста. Этот узел обычно является дочерним по отношению к заголовку, элементу div, абзацу или пункту списка.

var txtNode=document.createTextNode("some text");

Согласно стандарту DOM текстовые узлы отличаются от узлов, представляющих HTML-элементы. К ним нельзя непосредственно применять стили, поэтому они занимают меньше памяти, чем обычные узлы. Стиль текста, соответствующего текстовому узлу, определяется стилем родительского DOMэлемента.

Чтобы созданный узел мог отображаться в окне браузера, его надо включить в состав документа. Для этого предусмотрен метод appendChild().

el.appendChild(childEl) ;

Методов createElement(), createTextNode() и appendChild() достаточно для добавления новых узлов в документу. Однако новые узлы нуждаются в стилях. Рассмотрим, какими способами можно добавить их.

82 Часть I. Новый взгляд на Web-приложение

2.4.4. Добавление стилей к документу

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

Выполняя действия с DOM, можно реализовать ряд визуальных эффектов для каждого элемента, например, задать его позицию, размеры, цвет, границы и обрамление. Модификация отдельных атрибутов позволяет управлять деталями отображения, однако эта процедура достаточно утомительна. Web-браузеры предоставляют средства, обеспечивающие необходимую точность при управлении интерфейсом из JavaScript-программы. Рассмотрим их более подробно.

Свойство className

Если элементы стилей созданы в результате выполнения кода программы, мы можем воспользоваться свойством className узла DOM. Ниже приведена строка кода, в результате выполнения которой к узлу применяются стили, определенные посредством класса declared.

hello.className='declared' ;

Здесь hello — это ссылка на узел DOM. Таким способом можно связывать с узлом любое количество правил CSS и управлять сложными стилями.

Свойство style

В некоторых случаях бывает необходимо изменить стиль конкретного элемента, т.е. модифицировать стиль, уже заданный средствами CSS.

С каждым узлом DOM связан ассоциативный массив style, содержащий информацию о стилях, установленных для данного узла. Как видно на рис. 2.4, в массиве стилей DOM-узла обычно содержится большое число элементов. Заметьте, что при присвоении значения свойству className узла автоматически модифицируются значения в массиве style.

Значениями массива style можно управлять непосредственно. Ниже показано, как отобразить рамку вокруг узла empty, задавая его стили.

empty.style.border="solid green 2px"; empty.style.width="200px";

Мы можем определить класс box и применить его посредством свойства className, но в ряде случаев описанный здесь подход проще и позволяет получить результаты быстрее. Кроме того, он позволяет формировать необходимые строки в программе. Если нам надо изменять размеры элементов с точностью до пикселя, то определять стили для значений ширины в интервале от 1 до 800 слишком сложно и неэффективно.

Используя рассмотренные выше способы, мы можем создавать новые элементы DOM и определять их стили. Существует еще один инструмент, позволяющий управлять содержимым документа. Он реализует альтернативный подход к решению задачи формирования Web-страницы с помощью программы. Рассмотрим свойство innerHTML.

Глава 2. Знакомство с Ajax

83

НЙ Ь W o r l d !

Рис. 2.4. Данные, соответствующие атрибуту s t y l e DOM-узла и отображаемые с помощью DOM Inspector. Большинство значений было установлено по умолчанию. Обратите внимание на полосу прокрутки: на экране отображается приблизительно четверть всех поддерживаемых стилей

2.4.5. Свойство innerHTML

Описанные выше методы обеспечивают управление структурой D0M на низком уровне. Методы createElement () и appendChild() лучше всего подходят тогда, когда документ имеет регулярную структуру и процедура создания документа легко формализуема. Все популярные браузеры поддерживают также innerHTML — свойство DOM-элементов. Это свойство позволяет без труда включить в состав элемента произвольное содержимое. Значением свойства innerHTML является строка, представляющая дочерние узлы в формате HTML. Используя данное свойство, мы можем переписать функцию addNode следующим образом:

function addListItemUsingInnerHTML(el,text){ el.innerHTML+="<div class='programmed1>"+text+"</div>";

}

Элемент div и содержащийся в нем текстовый узел можно добавить с помощью одного выражения. Заметьте также, что строка не присваивается свойству непосредственно, а добавляется к нему с помощью оператора +=. Чтобы удалить узел путем редактирования свойства innerHTML, надо извлечь значение и организовать его разбор. Свойство innerHTML применимо

84 Часть I. Новый взгляд на Web-приложение

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

Мы рассмотрели технологии JavaScript, CSS и DOM, которые давно известны как Dynamic HTML. Как было замечено в начале данной главы, Ajax использует многие средства, характерные для Dynamic HTML, но, кроме того, реализует принципиально новые возможности. В следующем разделе мы рассмотрим механизм, отличающий Ajax от DHTML, — средства взаимодействия с сервером в процессе работы пользователя.

2.5. Асинхронная загрузка с использованием XML

При работе с приложением, в особенности независимым, взаимодействие с ним является частью процесса решения задачи, поставленной перед пользователем. В главе 1 мы говорили о том, насколько важен хороший интерфейс. Если на время выполнения длительных вычислений приложение перестает реагировать на действия пользователя, последнему неминуемо приходится отвлекаться от решения основной задачи. Мы также обсуждали преимущества асинхронных вызовов и способы обеспечения отклика программы при сложных вычислениях и выяснили, что вследствие неустранимой задержки, связанной с работой в сети, все обращения к серверу следует считать длительными операциями. Мы также обратили ваше внимание на то, что модель, предполагающая обмен в виде HTTP-запросов и ответов на них, не позволяет создавать интерфейсы высокого качества. В классических Web-приложениях каждое обращение к серверу сопровождается полным обновлением текущей Web-страницы, в результате чего нормальная последовательность действий пользователя часто прерывается.

Несмотря на то что мы не можем сократить время, которое проходит от передачи запроса серверу до получения ответа от него, существуют способы передачи запросов в асинхронном режиме; при этом пользователь может продолжать работу с приложением. Первой попыткой решить подобную задачу было взаимодействие в фоновом режиме с использованием элементов I Frame. Впоследствии было найдено лучшее решение — использование объекта XMLHttpRequest. Ниже мы рассмотрим обе технологии.

2.5.1. Элементы IFrame

С появлением четвертой версии браузеров Netscape Navigator и Microsoft Internet Explorer стали доступны средства DHTML, обеспечивающие возможность компоновки Web-страницы из программы. Естественным расширением системы фреймов HTML стал элемент I Frame. В его названии первая буква условно означает inline (встроенный), т.е. фрейм является элементом другого документа, а не его полноправным "соседом". IFrame представляется как элемент древовидной структуры DOM, а это значит, что его можно перемещать, изменять размеры и даже скрыть, причем остальная часть страницы останется видимой. Тот факт, что с элементом I Frame можно связывать стили