Тема: Основные принципы создания интерактивных сайтов
План
Тема: Объектная модель документа
1. Понятия: объект, свойство, метод
2. Объектная модель документа
3. Правила написания web-сценария
Основная литература: [1, 5, 6, 12, 13, 20, 23, 32, 35]
Дополнительная литература: [16, 19, 31, 51]
Выше были рассмотрены два вида переменных: обычные переменные, иначе говоря, скаляры и массивы. Скаляры могут содержать только одно значение, массивы же — множество пронумерованных значений, доступ к которым можно получить по их номеру — индексу. И скаляры, и массивы находят свое применение в программах на JavaScript; нет смысла рассказывать, в каких случаях что применять, — это и так очевидно. Давайте лучше поговорим еще об одном виде переменных, которого мы до сих пор не касались.
Это объекты.
Объектом называется сложный тип данных, содержащий не какое-то одно значение, а целую сущность. Эта сущность может иметь набор свойств и методов, с помощью которых программа может ей управлять; свойство -это своего рода переменная, принадлежащая объекту, а метод — функция, также принадлежащая объекту и выполняющая над ним какие-либо действия. Объект (и сущность, содержащаяся в нем) представляет собой "вещь в себе"; ее внутренняя структура и принцип действия неизвестны использующему объект программисту.
В качестве примера объекта можно рассмотреть прекрасно знакомый вам Web-обозреватель. У него есть свойство "адрес" и метод "открыть Web-страницу, которой принадлежит этот адрес". Вы можете присвоить этом свойству нужный адрес, а также можете его оттуда считать и присвоить какой-либо переменной или использовать иным способом:
currentWebBrowser.address = "http://www.w3c.org"; currAddr = currentWebBrowser.address + "/сss/";
Именно такой синтаксис используется для доступа к свойствам: <имя объеках <имя свойства> (не забудьте поставить знак точки). В первом случае мы поместили в свойство address объекта currentWebBrowser строку с интернет-адресом комитета WWWC. Во втором случае мы извлекли из этого свойства находящийся в нем адрес, прибавили к нему справа текст "/сss/" и присвоили переменной currAddr. (Как видите, для слияния (или конкатенации) строк использовался оператор +.)
Для вызова метода используется аналогичный синтаксис: <имя объекта>. <имя метода> (). Сейчас мы вызовем метод до вышеупомянутого объекта:
currentWebBrowser.gо ();
Метод до — не что иное, как обычная функция. В данный момент возвращенное ей значение игнорируется, но в других случаях оно может использоваться. Также метод, как и любая функция, может принимать параметры:
currentWebBrowser.goTo("http://www.w3c.org");
Таким образом мы можем управлять Web-обозревателем. И — заметьте -ничего не зная о его внутреннем устройстве. Более того, мы не обязаны о нем знать. Использование объектов как раз и направлено на то, чтобы позволить программистам пользоваться различными инструментами и дополнительными компонентами, не зная их внутреннего устройства, а также создавать такие инструменты и компоненты для своих коллег.
Говорят, что JavaScript — объектно-ориентированный язык программирования, т. к. использует объекты. Этим он отличается от обычных, процедурных языков, которые используют только функции.
Каждый объект перед тем, как с ним можно будет работать, должен быть создан. Выполняется это с помощью оператора создания объекта new.
var currentWebBrowser; currentWebBrowser= new WebBrowser();
Здесь объявляется переменная currentWebBrowser и ей присваивается вновь созданный с помощью оператора new объект. Этот объект создан на основе класса WebBrowser, который является как бы шаблоном для создаваемых объектов. A currentWebBrowser также иногда называется экземпляром класса
WebBrowser.
Удалить ненужный объект можно с помощью метода delete.
currentWebBrowser.delete();
Имейте в виду, что ненужные объекты, созданные вами, всегда надо удалять, чтобы освободить ресурсы системы. Исключение составляют только истемные объекты, создаваемые самим интерпретатором или предоставляемые интерпретатору Web-обозревателем. Если вы попытаетесь удалить системный объект, интерпретатор выдаст сообщение об ошибке. О системных объектах мы поговорим ниже.
Но каким же образом создаются классы объектов? Исключительно просто. Более того, если бы остальные языки объектно-ориентированного программирования увидели, как легко создаются классы в JavaScript, они бы умерли от зависти. Взглянем еще раз на выражение, с помощью которого создаются объекты:
currentWebBrowser = new WebBrowser();
Согласитесь, это сильно напоминает вызов функции. Но дело в том, что WebBrowser — и есть функция, только специальным образом написанная. Она называется конструктором класса. Давайте напишем конструктор для класса WebBrowser.
function WebBrowser() {
this.address = "http://www.server.ru/my_home_page.htm";
}
Этот код создает в классе WebBrowser одно-единственное свойство address. Обратите внимание на синтаксис, с помощью которого это делается. В качестве имени класса используется ключевое слово this, обозначающее текущий класс. Интерпретатор JavaScript создает свойства класса сразу же при первом обращении к ним; вот и в нашем случае он создал свойство address и дал ему значение, присвоенное нами. Конструктор может принимать параметры:
function WebBrowser(homePage) { this.address = homePage;
}
Таким образом мы можем передать конструктору класса адрес домашней страницы, с которой начнется путешествие по Интернету.
var currentWebBrowser;
currentWebBrowser = new WebBrowser("http://www.server.ru/home_page.htm");
"Но, позвольте! — скажете вы. — А как же создаются методы класса?" Тоже очень просто.
Прежде всего, нам нужно написать функцию, реализующую этот метод.
function fGoTo(pageAddress) { this.address = pageAddress;
Мы назвали эту функцию fGoTo. Это имя состоит из буквы f (от англ. function — функция) и имени метода дото, который она реализует.
Теперь перепишем функцию-конструктор таким образом, чтобы создать новый метод дото.
function WebBrowser(homePage) {
this.address = homePage;
this.goTo = fGoTo; }
Как видите, мы "присваиваем" написанную нами функцию fGoTo свойству дото класса WebBrowser. После этого можно вызывать метод дото этого класса.
var currentWebBrowser;
currentWebBrowser = new WebBrowser("http://www.server.ru/home_jpage.htm");
currentWebBrowser.goTo("http://www.w3c.org");
Только что вы научились создавать простейшие классы. Но на самом деле вам в очень редких случаях придется делать это. Куда чаще вы будете пользоваться уже готовыми системными классами, предоставляемыми самим интерпретатором JavaScript и другими программами, например Web-обозревателем. Поэтому давайте поговорим о системных классах.
Системных классов, предоставляемых программисту интерпретатором, довольно много. Среди них есть, например, класс Date, предназначенный для работы со значениями даты и времени.
var d;
d = new Date () ;
Только что мы создали объект класса Date. Так как мы не передали параметр в функцию конструктора этого класса, интерпретатор поместил в этот объект значение текущей даты. После этого можно, например, узнать номер дня недели:
var dayNumber; dayNumber = d.getDay(};
Или выяснить год:
var year;
year = d.getFullYear();
Некоторые методы класса Date перечислены в табл. 13.1.
Как видите, класс Date предусматривает полный набор методов для работы со значениями даты и времени. Другие системные классы также имеют достаточно большие наборы свойств и методов, которые мы не будем здесь рассматривать.
Таблица 13.1.Некоторые методы класса Date
Метод | Описание | ||
getDate ( ) | Возвращает число | ||
getDay ( ) | Возвращает цифру, обозначающую день недели (0 — воскресенье, 1 — понедельник, 2 — вторник и т. д.) | ||
getFullYear() | Возвращает год | ||
getHours ( ) | Возвращает час | ||
getMilliseconds ( ) | Возвращает миллисекунды | ||
getMinutes ( ) | Возвращает минуты | ||
getMonth ( ) | Возвращает цифру, обозначающую месяц (от 0 до 11) | ||
getSeconds ( ) | Возвращает секунды | ||
getTime ( ) | Возвращает время в виде количества миллисекунд, прошедших с полуночи 1 января 1 970 года | ||
Системный класс Math — другого рода. Он включает набор свойств и методов, реализующих различные математические и тригонометрические функции. Единственный его объект создается самим интерпретатором JavaScript при запуске и уничтожается при завершении работы. Так что вам не нужно самим создавать объекты этого класса. Это как раз типичный случай системного объекта.
var f;
f = Math.sin(Math.PI);
В результате вычисления вышеприведенного выражения в переменной f окажется значение sin (я).
Существуют также системные классы Number и string, служащие для хранения данных соответственно числового и строкового форматов, и несколько других системных классов, используемых значительно реже.
Язык JavaScript имеет одну любопытную особенность. Дело в том, что любая переменная обычного типа данных может быть представлена как объект какого-либо класса. Давайте, например, рассмотрим следующий код:
var s, 1;
s = "JavaScript";
1 = s.length;
Здесь мы сначала помещаем в переменную s строку "JavaScript", а потом вызываем свойство length этой переменной. В таком случае интерпретатор
считает переменную s объектом класса string и беспрепятственно "пускает" нас к свойству length этого класса, возвращающему длину строки текста, которую мы и помещаем в переменную 1.
Аналогичный "финт" можно проделать и с числовой величиной:
var a, s;
а = 16765247;
s = a.toString();
Здесь вызываем метод toString класса Number, возвращающий строковое представление числа.
Раньше говорилось, что, помимо интерпретатора JavaScript, системные классы могут представляться также и другими программами. К числу этих самых "других" программ относится Web-обозреватель. Его классы и системные объекты — это что-то особенное...
Давайте посмотрим на какую-нибудь Web-страницу. Что она собой представляет? Фактически, иерархию элементов. Мельчайшие элементы страницы, например текстовые абзацы, являются потомками более крупных и сложных элементов, например, свободно позиционируемых элементов. Свободные элементы, в свою очередь, могут находиться в других свободных элементах или непосредственно в самой странице. Получается весьма сложная многоуровневая структура, в которой одни элементы зависят от других.
Описать такую структуру можно с помощью объектов. Точнее, сложной иерархии объектов, вложенных друг в друга и зависящих друг от друга. Такая структура называется объектной моделью документа (Document Object Model, DOM). Все современные программы Web-обозревателей представляют Web-страницу как иерархический набор объектов.
Какое преимущество дает пользователям такой подход? Никакого. Все это рассчитано только на программистов, разрабатывающих Web-сценарии.
Каждый из объектов, из которых состоит Web-страница, имеет набор свойств, предоставляющих доступ к значениям различных атрибутов соответствующего тега, методов, с помощью которых этим объектом можно манипулировать, и событий, которые могут в этом объекте происходить и которые можно обрабатывать. Это позволяет управлять практически любым элементом страницы, самой страницей и даже самим Web-обозревателем, используя специально написанные Web-сценарии.
Например, именно таким образом на Web-странице создаются анимирован-ные элементы (см. главу 12). Также с помощью сценариев можно изменять цвета, параметры шрифта и даже само содержимое элементов страницы. Более того, так можно управлять и самим Web-обозревателем: открывать и закрывать вспомогательные окна, перемещаться взад-вперед по списку "истории" и даже принудительно загружать нужные Web-страницы без участия пользователя.
Неужели вы думали, что Web-программисты пройдут мимо такой возможности! Если вы думаете, что пройдут, — вы плохо их знаете. Вспомните, например, что говорилось в предыдущей главе об анимации. Едва появилась возможность немного подвигать по странице тем или иным рисунком, как Web-программисты эту возможность реализовали. А сейчас анимацию поддерживают даже Web-редакторы, и Dreamweaver тому пример.
Но хватит говорить на отвлеченные темы! Давайте все-таки займемся объектной моделью документа.
Сначала выясним, каким образом можно получить доступ к нужному элементу. Для этого ему необходимо дать уникальное имя. Делается это с помощью атрибута ID или NAME. Атрибут ID поддерживается практически всеми тегами HTML, атрибут NAME — только некоторыми. К тегам, поддерживающим этот атрибут, относятся формы, элементы управления, фреймы, гиперссылки и некоторые другие.
Но почему же нельзя пользоваться только атрибутом ID? Все дело в проклятой несовместимости Navigator 4.x и интернет-стандартов. Старые версии Navigator используют атрибут ID только для присвоения элементам стилей, а для задания имен признают только атрибут NAME.
Дав с помощью атрибутов ID или NAME элементу страницы уникальное имя. вы можете обращаться к нему из сценария, вызывая его методы и свойства. Интерпретатор сам найдет нужный элемент по его имени. Для доступа к элементу страницы в Internet Explorer используется синтаксис:
<Имя элемента, заданное в атрибутах ID или NAME>.<Свойство или метод>
Если же вы пишете сценарий для Navigator 4.x, делайте так:
document["<Имя элемента, заданное в атрибуте NAME>"].<Свойство или метод>
Давайте приведем небольшой пример, поясняющий вышесказанное.
<Р ID="para" STYLE="color: #0000FF">Некий текст.</Р>
Сначала мы создали текстовый абзац, назвали его para (обратите внимание на значение атрибута ID) и присвоили ему встроенный стиль, задающий цвет текста. Сейчас мы этот цвет текста изменим, воспользовавшись Web-сценарием.
para.style.color = "#FF0000";
Здесь нужны дополнительные пояснения. Дело в том, что каждый элемент страницы в объектной модели документа имеет внутренний объект style, дающий доступ к его встроенному стилю. Обратиться к этому объекту можно через одноименное свойство, что мы и сделали. А уж объект style предоставляет доступ ко всем атрибутам встроенного стиля через одноименные свойства. В данном примере для получения доступа к значению атрибута стиля color использовалось свойство color.
Вы можете изменить выравнивание текста этого абзаца, обратившись к свойству align:
para. align = "center";
Свойство align предоставляет доступ к значению атрибута ALIGN тега <р>.
К несчастью, вышеприведенный пример будет работать только в самых последних программах Web-обозревателей. Пресловутый Navigator 4.x не позволяет изменять внешний вид и содержимое элементов страницы после ее загрузки. Исключение составляют только графические изображения, фреймы и слои.
А вот этот код будет работать везде:
<IMG NAME=" some Image" SRC="image1.gif ">
document ["someImage"] .src = "image2.gif";
Он меняет файл, содержимое которого отображается в элементе графического изображения, на другой. Для этого он присваивает иное значение свойству src объекта somelmage, предоставляющее доступ к атрибуту SRC тега
<IMG>.
Чтобы получить доступ к самой Web-странице, воспользуйтесь системным объектом document. В частности, вы можете задать цвет гиперссылок, воспользовавшись свойством linkColor, предоставляющим доступ к значению атрибута LINK тега <BODY>:
document.linkColor = "#FF0000";
Оба рассмотренных нами объекта представляют собой соответственно видимый элемент страницы и саму страницу. Оба этих объекта были созданы с помощью тегов HTML. Теперь же мы начнем рассмотрение объектов, не являющихся элементами страницы. Это объекты Web-обозревателя, не видимые пользователю.
Объект document имеет внутренний объект location, предоставляющий доступ к интернет-адресу страницы и различным его частям. Доступен он через одноименное свойство. Воспользовавшись этим объектом, мы можем узнать, с какого интернет-адреса была загружена данная страница:
address = document.location.href;
выяснить имя файла этой страницы:
filename = document.location.pathname;
либо загрузить другую страницу:
document.location.href = "http://www.othersite.ru/otherpage.htm";
Объект window представляет текущее окно Web-обозревателя либо текущий фрейм, если страница загружена во фрейме. С помощью этого объекта вы можете, например, закрыть это окно:
window.close();
или заменить текст, отображаемый в его строке статуса:
window.status = "Сейчас работает Web-сценарий!";
Объект window имеет внутренний объект navigator, предоставляющий доступ к самой программе Web-обозревателя. Доступен он через одноименное свойство. Воспользовавшись этим объектом, мы можем выяснить, например, версию программы:
version = window.navigator.appVersion; или название:
programName = window.navigator.appName;
Объект window имеет внутренний объект history, предоставляющий доступ к списку "истории" Web-обозревателя. Он доступен также через одноименное свойство. Воспользовавшись этим объектом, мы можем "путешествовать" по списку "истории" вперед:
window.history.forward();
и назад:
window.history.back();
Вот и закончился ликбез по JavaScript и объектной модели документов. Пришло время поговорить о том, как же пишутся Web-сценарии.
Прежде всего, выясним, как JavaScript-код помещается в HTML-код. Для этого служит парный тег <SCRIPT>. . .</SCRIPT>, внутри которого помещается код сценария. Вне этого тега помещать сценарий можно, но выполняться он не будет.
Вообще, все Web-сценарии можно разделить на два вида: выполняющиеся при загрузке страницы (загрузочные) и вызывающиеся в ответ на событие (обработчики событий). В зависимости от того, является сценарий загрузочным или обработчиком, различается способ его реализации.
Сценарии, выполняющиеся при загрузке страницы, представляют собой обычный код на JavaScript, помещенный в тег <SCRIPT>. Он имеет такой вид:
<FORM ACTION="http://www.somesite.ru/cgi/prograra.p1">
<INPUT TYPE="text" NAME="txtDate"> <SCRIPT> var d;
d = new Date ();
document.forms[0].txtDate.value = d.toString(); </SCRIPT> </FORM>
Этот сценарий помещает в поле ввода txtDate значение текущей даты. (О формах и элементах управления см. главу 16.) Для этого он вызывает свойство value, отображающее значение, введенное в поле ввода. Заметьте, что для именования поля ввода мы использовали атрибут NAME, поэтому вышеприведенный код будет работать также и в Navigator 4.x.
Этот сценарий будет выполняться непосредственно при загрузке страницы. Сначала Web-обозреватель загрузит и распознает тег <FORM>, потом — тег <INPUT>, а сразу за ним выполнит наш сценарий. Такие сценарии очень часто используются для занесения начальных значений в элементы управления и вообще для выполнения различных предустановок.
Мы поместили код сценария сразу же за тегом, задающим поле ввода, к которому мы обращаемся. Если бы мы поместили сценарий перед тегом, Web-обозреватель не смог бы найти объект txtDate, т. к. он еще не был бы создан, и выдал бы сообщение об ошибке. Имейте это в виду, когда будете писать загрузочные сценарии.
Если нужно, чтобы какие-либо предустановки выполнились перед тем, как будет загружен какой-либо "видимый" на странице HTML-код, выполняющий их сценарий помещается в секцию HTML-заголовка страницы (тег <HEAD>). В основном, это касается кода, выполняющего предустановки для других сценариев, чаще всего, обработчиков событий.
Теперь поговорим о сценарии обработчика событий. И рассмотрим пример такого обработчика:
<HEAD>
<SCRIPT>
function para_onClick() {
para.style.color = "#FF0000"; }
</SCRIPT> </HEAD> <BODY>
<P ID="para" STYLE="color: #0000FF" onClick="para_ondick();">Некий текст.</Р>
</BODY>
Это как раз пример сценария, помещаемого в секцию HTML-заголовка страницы. Он представляет собой функцию para_ondick, чей код меняет цвет текста абзаца para. Поместив сценарий в секцию HTML-заголовка, мы можем быть уверены, что Web-обозреватель обработает этот код перед тем, как будет загружена страница, и "отложит" определения функций в "долгий ящик", чтобы вызвать их впоследствии, при наступлении соответствующего события.
А теперь обратимся к нашему текстовому абзацу. Что видим? Нечто странное... Откуда-то взялся новый, не знакомый нам атрибут onclick. Что он делает?
Это не совсем атрибут. Вернее, совсем не атрибут, хотя и выглядит похоже. Таким способом в HTML к какому-либо событию, происходящему в элементе страницы, привязывается обработчик. Общий синтаксис такой "привязки" следующий:
<Имя события>="<Код сценария обработчика>"
В данном случае мы привязали вызов функции para_onclick в качестве обработчика к событию onclick, происходящему, когда пользователь щелкает мышью по этому абзацу.
Вообще, код этого обработчика столь мал, что его можно без всяких последствий поместить прямо в тег <р>:
<Р ID="para" STYLE="color: #0000FF" onClick="para.style.color = #'FF0000';">Heкий текст.</Р>
Таким образом, мы значительно уменьшим размер HTML-кода страницы, что нам совсем не помешает.
Лекция №10 (2 часа)