4. Программируем свойства окна браузера. JavaScript (от intuit.ru)
Рассматриваются вопросы программирования свойств окна браузера, управление окнами, а также работа с фреймами.
Объект window
Класс объектов Window - это самый старший класс в иерархии объектов JavaScript. Объект window, относящийся к текущему окну (т.е. в котором выполняется скрипт), является объектом класса Window. Класс объектов Frame содержится в классе Window, т.е. каждый фрейм - это тоже объект класса Window.
О фреймах речь пойдет ниже, а пока вернемся к объекту window. Объект window создается только в момент открытия окна. Все остальные объекты, которые порождаются при загрузке страницы, есть свойства объекта window. Более того, все глобальные переменные, определенные в данном окне, тоже являются свойствами объекта window. Таким образом, у объекта window могут быть разные свойства при загрузке разных страниц. Кроме того, в разных браузерах свойства объектов и поведение объектов и браузера при обработке событий может быть различным. При программировании на JavaScript чаще всего используют следующие свойства, методы и события объекта window:
Свойства | Методы | События |
---|---|---|
status defaultStatus location history navigator document frames[] opener parent self top |
open() close() focus() blur() alert() confirm() prompt() setTimeout() setInterval() clearTimeout() clearInterval() |
Load Unload Focus Blur Resize Error |
Поскольку объект window является самым старшим, то в большинстве случаев при обращении к его свойствам и методам приставку "window." можно опускать (разумеется, в случае, если вы хотите обратиться к свойству или методу текущего окна, где работает скрипт; если же это другое окно, то необходимо указать его идентификатор). Так, например, можно писать alert('Привет') вместо window.alert('Привет'), или location вместо window.location. Исключениями из этого правила являются вызовы методов open() и close(), у которых нужно указывать имя окна, с которым работаем (родительское в первом случае и дочернее во втором). Свойства frames[], self, parent и top будут рассмотрены в разделе, посвященном фреймам. Свойство opener будет рассмотрено при описании метода window.close().
Свойства объекта window
Поле статуса и свойство window.status
Поле статуса - это первое, что начали использовать авторы HTML-страниц из арсенала JavaScript. Калькуляторы, игры, математические вычисления и другие элементы выглядели слишком искусственно. На их фоне бегущая строка в поле статуса была изюминкой, которая могла действительно привлечь внимание пользователей к Web-узлу. Постепенно ее популярность сошла на нет. Бегущие строки стали редкостью, но программирование поля статуса встречается на многих Web-узлах.
Рис.4.1. Поле статуса
Полем статуса (status bar) называют поле нижней части окна браузера сразу под областью отображения HTML-страницы. В поле статуса отображается информация о состоянии браузера (загрузка документа, загрузка графики, завершение загрузки, запуск апплета и т.п.). Программа на JavaScript имеет возможность работать с этим полем как с изменяемым свойством окна. При этом фактически с ним связаны 2 разных свойства:
Значение свойства status можно изменить - и оно тут же будет отображено в поле статуса. Свойство defaultStatus тоже можно менять - и сразу по его изменении оно отображается в поле статуса.
Разница между этими 2 свойствами заключается в их поведении: если свойству status присвоить пустую строку: window.status="", то в поле статуса автоматически будет отображено значение defaultStatus. Обратного же не происходит: при присвоении пустой строки свойству defaultStatus оно и отобразится в поле статуса, независимо от значения свойства status. Следует отметить, что реакция браузеров на описываемые ниже действия со свойствами status и defaultStatus может быть разной в различных браузерах.
Программируем status
Свойство status связано с отображением сообщений о событиях, отличных от простой загрузки страницы. Например, в IE при наведении указателя мыши на ссылку обработчик onMouseOver помещает в поле статуса значение URL, указанное в атрибуте HREF этой ссылки (при этом никак не меняя значения свойств status и defaultStatus). При попадании же курсора мыши на область, свободную от ссылок, обработчик onMouseOut возвращает в поле статуса значение defaultStatus, при условии, что оно не есть пустая строка (опять же никак не меняя значений обоих свойств). Мы можем изменить это поведение, например, как в следующем примере:
<A onMouseOver="window.status='Мышь над ссылкой';return true;" onMouseOut="window.status='Мышь увели со ссылки';" HREF="//site.com/">Наведите мышь на ссылку и следите за полем статуса</A>
Обратите внимание на оператор return true в конце обработчика событий onMouseOver. Он необходим для того, чтобы отменить действие по умолчанию (в данном случае - вывод URL в поле статуса), которое, в отсутствие этого оператора, браузер выполнил бы сразу после вывода нами своей строки в поле статуса, и пользователь не успел бы увидеть нашу строку. Аналогичный трюк отмены действия по умолчанию годится и для некоторых других событий (onClick, onKeyDown, onKeypress, onMouseDown, onMouseUp, onSubmit, onReset), с той лишь разницей, что для перечисленных обработчиков отмена выполняется оператором return false.
Для обработчика onMouseOut такого способа отменить действие по умолчанию не существует (к сожалению). Но в данном конкретном случае это не требуется - как уже было сказано, при уводе курсора со ссылки в поле статуса восстанавливается значение defaultStatus только в случае, если это значение не есть пустая строка. Но в нашем случае (по умолчанию при загрузке страницы в IE) оно равно именно пустой строке. Поэтому, уводя курсор с нашей ссылки, мы продолжаем видеть в поле статуса строку "Мышь увели со ссылки". Ситуация изменится в следующем примере, когда мы предварительно зададим свое (непустое) значение defaultStatus.
Программируем defaultStatus
Свойство defaultStatus определяет текст, отображаемый в поле статуса, когда никаких событий не происходит. Дополним предыдущий пример изменением этого свойства в момент окончания загрузки документа, т.е. в обработчике onLoad:
<BODY onLoad="window.defaultStatus='Значение по умолчанию';"> <A onMouseOver="window.status='Мышь над ссылкой';return true;" onMouseOut="window.status='Мышь увели со ссылки'; alert('Ждем');" HREF="//site.com/">Наведите мышь на ссылку и следите за полем статуса</A>
Сразу после загрузки документа в поле статуса будет "Значение по умолчанию". При наведении указателя мыши на ссылку в поле статуса появится надпись "Мышь над ссылкой", при этом URL ссылки (http://site.com/) в поле статуса не появится, т.к. мы подавили его вывод оператором return true.
При убирании указателя мыши со ссылки пользователь бы не успел увидеть строку "Мышь увели со ссылки", поскольку действие по умолчанию (вывод значения defaultStatus в поле статуса) не подавлено (и не может быть подавлено - у обработчика onMouseOut нет такой возможности). Однако мы ввели оператор вывода окна предупреждения alert('Ждем') (он рассматривается ниже) - и теперь пользователь будет видеть в поле статуса строку "Мышь увели со ссылки" до тех пор, пока не нажмет OK на этом окне.
Поле адреса и свойство window.location
Поле адреса в браузере обычно располагается в верхней части окна и отображает URL загруженного документа. Если пользователь хочет вручную перейти к какой-либо странице (набрать ее URL), он делает это в поле адреса.
Рис.4.2. Поле адреса (location)
Свойство location объекта window само является объектом класса Location. Класс Location, в свою очередь, является подклассом класса URL, к которому относятся также объекты классов Area и Link. Объекты Location наследуют все свойства объектов URL, что позволяет получить доступ к любой части схемы URL. Подробнее о классе объектов URL мы расскажем в лекции 6.
В целях совместимости с прежними версиями JavaScript, в языке поддерживается также свойство window.document.location, которое в настоящее время полностью дублирует свойство window.location со всеми его свойствами и методами. Рассмотрим теперь свойства и методы объекта window.location (событий, связанных с этим объектом, нет).
Свойства объекта location
Их проще продемонстрировать на примере. Предположим, что браузер отображает страницу, расположенную по адресу:
http://1.ru:80/dir/page.cgi?product=phone&id=3#mark
Тогда свойства объекта location примут следующие значения:
window.location.href="//1.ru:80/dir/page.cgi?product=phone&id=3#mark" window.location.protocol="http:" window.location.hostname="1.ru" window.location.port=80 window.location.host="1.ru:80" window.location.pathname="dir/page.cgi" window.location.search="?product=phone&id=3" window.location.hash="#mark"
Как уже говорилось в предыдущих лекциях, к свойствам объектов можно обращаться как с помощью точечной нотации (как выше), так и с помощью скобочной нотации, например: window.location['host'].
Методы объекта location
Методы объекта location предназначены для управления загрузкой и перезагрузкой страницы. Это управление заключается в том, что можно либо перезагрузить текущий документ (метод reload()), либо загрузить новый (метод replace()).
window.location.reload(true);
Метод reload() полностью моделирует поведение браузера при нажатии на кнопку Reload в панели инструментов. Если вызывать метод без аргумента или указать его равным true, то браузер проверит время последней модификации документа и загрузит его либо из кеша (если документ не был модифицирован), либо с сервера. Такое поведение соответствует простому нажатию кнопки Reload браузера (клавиши F5 в IE). Если в качестве аргумента указать false, то браузер перезагрузит текущий документ с сервера, несмотря ни на что. Такое поведение соответствует одновременному нажатию клавиши Shift и кнопки браузера Reload (или Ctrl+F5 в IE).
Используя объект location, перейти на новую страницу можно 2 способами:
window.location.href="//www.newsite.ru/"; window.location.replace("//www.newsite.ru/");
Разница между ними - в отображении этого действия в истории посещений страниц window.history. В первом случае в историю посещений добавится новый элемент, содержащий адрес "//www.newsite.ru/", так что при желании можно будет нажать кнопку Back на панели браузера, чтобы вернуться к прежней странице. Во втором случае новый адрес "//www.newsite.ru/" заместит прежний в истории посещений, и вернуться к прежней странице нажатием кнопки Back уже будет невозможно.
История посещений (history)
История посещений страниц World Wide Web позволяет пользователю вернуться к странице, которую он просматривал ранее в данном окне браузера. История посещений в JavaScript трансформируется в объект window.history. Этот объект указывает на массив URL-страниц, которые пользователь посещал и которые он может получить, выбрав из меню браузера режим Go. Методы объекта history позволяют загружать страницы, используя URL из этого массива.
Чтобы не возникло проблем с безопасностью браузера, путешествовать по History можно, только используя индекс. При этом URL, как текстовая строка, программисту недоступен. Чаще всего этот объект используют в примерах или страницах, на которые могут быть ссылки из нескольких разных страниц, предполагая, что можно вернутся к странице, из которой пример будет загружен:
<FORM><INPUT TYPE="button" VALUE="Назад" onClick="history.back()"></FORM>
Данный код отображает кнопку "Назад", нажав на которую, мы вернемся на предыдущую страницу. Аналогичным образом действует метод history.forward(), перенося нас на следующую посещенную страницу.
Существует также метод go(), имеющий целочисленный аргумент и позволяющий перескакивать на несколько шагов вперед или назад по истории посещений. Например, history.go(-3) перенесет нас на 3 шага назад в истории просмотра. При этом методы back() и forward() равносильны методу go() с аргументами -1 и 1, соответственно. Вызов history.go(0) приведет к перезагрузке текущей страницы.
Тип браузера (navigator)
Часто возникает задача настройки страницы на конкретную программу просмотра (браузер). При этом возможны 2 варианта: определение типа браузера на стороне сервера, либо на стороне клиента. Для последнего варианта в арсенале объектов JavaScript существует объект window.navigator. Важнейшие из свойств этого объекта перечислены ниже.
Свойство | Описание |
---|---|
userAgent | Основная информация о браузере. Передается серверу в HTTP-заголовке при открытии пользователем страниц |
appName | Название браузера |
appCodeName | Кодовое название браузера |
appVersion | Данные о версии браузера и совместимости |
Рассмотрим простой пример определения типа программы просмотра:
<FORM><INPUT TYPE=button VALUE="Тип навигатора" onClick=alert(window.navigator.userAgent)></FORM>
При нажатии на кнопку отображается окно предупреждения, содержащее значение свойства navigator.userAgent. Если это значение разобрать по компонентам, то может получиться, например, следующее:
navigator.userAgent="Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1)" navigator.appName="Microsoft IE" navigator.appCodeName="Mozilla" navigator.appVersion="4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1)"
У объекта navigator есть еще несколько интересных с точки зрения программирования применений. Например, чтобы проверить, поддерживает ли браузер клиента язык Java, достаточно вызвать метод navigator.javaEnabled(), возвращающий значение true, если поддерживает, и false в противном случае.
Можно проверить, какие форматы графических файлов поддерживает браузер, воспользовавшись свойством navigator.mimeTypes (оно представляет собой массив всех типов MIME, которые поддерживаются данным браузером):
<SCRIPT> if(navigator.mimeTypes['image/gif']!=null) document.write('Ваш браузер поддерживает GIF<p>'); if(navigator.mimeTypes['image/tif']==null) document.write('Ваш браузер не поддерживает TIFF') </SCRIPT>
К сожалению, такая проверка не позволяет определить наличие возможности автоматической подгрузки графики.
Методы объекта window
Что можно сделать с окном? Открыть (создать), закрыть (удалить), положить его поверх всех других открытых окон (передать фокус). Кроме того, можно управлять свойствами окна и свойствами подчиненных ему объектов. Сосредоточимся на простых и наиболее популярных методах управления окнами.
alert()
Метод alert() позволяет выдать окно предупреждения, имеющее единственную кнопку "OK":
<A HREF="javascript:window.alert('Внимание')"> Повторите запрос!</A>
Нужно лишь иметь в виду, что сообщения выводятся системным шрифтом, следовательно, для получения предупреждений на русском языке нужна локализованная версия ОС.
confirm()
Метод confirm() позволяет задать пользователю вопрос, на который тот может ответить либо положительно (нажав кнопку "OK"), либо отрицательно (нажав кнопку "Отмена" или "Cancel", либо просто закрыв окно запроса). В соответствии с действиями пользователя метод confirm() возвращает значение true либо false. Пример:
<FORM NAME=f> <INPUT TYPE=button NAME=b VALUE="Нажмите эту кнопку" onClick="if(window.confirm('Вы знаете JavaScript?')) document.f.b.value='Да. Спросить еще?'; else document.f.b.value='Нет. Спросить еще?';"> </FORM>
Все ограничения для сообщений на русском языке, которые были описаны для метода alert(), справедливы и для метода confirm().
prompt()
Метод prompt() позволяет принять от пользователя cтроку текста. Синтаксис его таков:
prompt("Строка вопроса","Строка ответа по умолчанию")
Когда пользователь введет свой ответ (либо оставит неизменным ответ по умолчанию) и нажмет кнопку OK, метод prompt() возвратит полученную строчку в качестве значения, которое можно далее присвоить любой переменной и потом разбирать ее в JavaScript-программе.
<FORM NAME=f> <INPUT TYPE=button VALUE="Открыть окно ввода" onClick="document.f.e.value= window.prompt('Введите сообщение','Сюда');"> <INPUT SIZE=30 NAME=e> </FORM>
window.open()
Метод open() предназначен для создания новых окон. В общем случае его синтаксис выглядит следующим образом:
myWin=window.open("URL","имя_окна","параметр=значение,параметр=значение,...", заменить);
Первый аргумент задает адрес страницы, загружаемой в новое окно (можно оставить пустую строку, тогда окно останется пустым). 2-й аргумент задает имя окна, которое можно будет использовать в атрибуте TARGET контейнеров <A> и <FORM>. В качестве значений допустимы также зарезервированные имена _blank, _parent, _self, _top, смысл которых такой же, как у аналогичных значений атрибута TARGET. Если имя_окна совпадает с именем уже существующего окна (или фрейма), то новое окно не создается, а все последующие манипуляции с переменной myWin будут применяться к этому окну (или фрейму).
Третий аргумент есть не содержащая пробелов строка, представляющая собой список параметров и их значений, перечисленных через запятую. Указание каждого из параметров необязательно, однако значения по умолчанию могут зависеть от браузера, поэтому всегда указывайте явно те параметры, на которые рассчитываете. Возможные параметры перечислены в таблице 4.3. Вместо значений yes и no можно использовать 1 и 0. Последний аргумент "заменить" является необязательным, принимает значения true и false и означает: следует ли новый URL добавить в history в качестве нового элемента или заменить им последний элемент history.
Метод window.open() возвращает ссылку на вновь открытое окно, т.е. объект класса Window. Его можно присвоить переменной (что мы и сделали выше), с тем чтобы потом можно было управлять открытым окном (писать в него, читать из него, передавать и убирать фокус, закрывать).
Параметр | Значения | Описание |
---|---|---|
width | число | Ширина окна в пикселах (не менее 100) |
height | число | Высота окна в пикселах (не менее 100) |
left | число | Расстояние от левого края экрана до левой границы окна в пикселах |
top | число | Расстояние от верхнего края экрана до верхней границы окна в пикселах |
directories | yes/no | Наличие у окна панели папок (Netscape Navigator) |
location | yes/no | Наличие у окна поля адреса |
menubar | yes/no | Наличие у окна панели меню |
resizable | yes/no | Сможет ли пользователь менять размер окна |
scrollbars | yes/no | Наличие у окна полос прокрутки |
status | yes/no | Наличие у окна поля статуса |
toolbar | yes/no | Наличие у окна панели инструментов |
Приведем 2 примера открытия нового окна:
<FORM> <INPUT TYPE=button VALUE="Простое окно" onClick="window.open('', 'test1', 'directories=no,height=200,location=no,'+ 'menubar=no,resizable=no,scrollbars=no,'+ 'status=no,toolbar=no,width=200');"> <INPUT TYPE=button VALUE="Сложное окно" onClick="window.open('', 'test2', 'directories=yes,height=200,location=yes,'+ 'menubar=yes,resizable=yes,scrollbars=yes,'+ 'status=yes,toolbar=yes,width=200');"> </FORM>
При нажатии кнопки "Простое окно" получаем окно со следующими параметрами:
При нажатии кнопки "Сложное окно" получаем окно, где:
window.close()
Метод close() позволяет закрыть окно. Чаще всего возникает вопрос, какое из окон, собственно, следует закрыть. Если необходимо закрыть текущее, то:
window.close(); self.close();
Если мы открыли окно с помощью метода window.open(), то из скрипта, работающего в новом окне, сослаться на окно-родитель можно с помощью window.opener (обратите внимание, здесь window ссылается на объект нового, созданного окна, т.к. оно использовано в скрипте, работающем в новом окне). Поэтому, если необходимо закрыть родительское окно, т.е. окно, из которого было открыто текущее, то:
window.opener.close();
Если необходимо закрыть произвольное окно, то тогда сначала нужно получить его идентификатор:
id=window.open(); ... id.close();
Как видно из последнего примера, закрывают окно не по имени (значение атрибута TARGET тут ни при чем), а используют указатель на объект.
Методы focus() и blur()
Метод focus() применяется для передачи фокуса в окно, с которым он использовался. Передача фокуса полезна как при открытии окна, так и при его закрытии, не говоря уже о случаях, когда нужно выбирать окна. Рассмотрим пример.
Открываем окно и, не закрывая его, снова откроем окно с таким же именем, но с другим текстом. Новое окно не появилось поверх основного окна, так как фокус ему не был передан. Теперь повторим открытие окна, но уже с передачей фокуса:
<SCRIPT> function myfocus(a) {myWin=window.open('','example','width=300,height=200'); //открываем окно и заводим переменную с указателем на него. //Если окно с именем 'example' существует, то новое окно не создается, //а открывается поток для записи в имеющееся окно с именем 'example' if(a==1) {myWin.document.open();//открываем поток ввода в уже созданное окно myWin.document.write('<H1>Открыли окно в первый раз');//Пишем в этот поток } if(a==2) {myWin.document.open(); myWin.document.write('<H1>Открыли окно во 2-й раз')} if(a==3) {myWin.focus();//передаем фокус, а затем выполняем те же действия, //что и в предыдущем случае myWin.document.open(); myWin.document.write('<H1>Открыли окно в третий раз')} myWin.document.write('</H1>'); myWin.document.close()} </SCRIPT> <a href="javascript:myfocus(1);">Откроем окно и напишем в него что-то</a>, <p><p> <a href="javascript:myfocus(2);">напишем в него же что-то другое, но фокус не передадим</a>, <p><p> <a href="javascript:myfocus(3);">опять что-то напишем в него, но сперва передав ему фокус</a>.
Пример 4.1. Передача фокуса в новое окно
Поскольку мы пишем содержание нового окна из окна старого (родителя), то в качестве указателя на объект используем значение переменной myWin.
Чтобы увести фокус из определенного окна myWin, необходимо применить метод myWin.blur(). Например, чтобы увести фокус с текущего окна, где выполняется скрипт, нужно вызвать window.blur(). Эффект будет тот же, как если бы пользователь сам свернул окно нажатием кнопки в правом верхнем углу окна.
Метод setTimeout()
Метод setTimeout() используется для создания нового потока вычислений, исполнение которого откладывается на время (в миллисекундах), указанное вторым аргументом:
idt=setTimeout("JavaScript_код",Time);
Типичное применение этой функции - организация периодического изменения свойств объектов. Например, можно запустить часы в поле формы:
<SCRIPT> var Chasy_idut=false; function myclock() {if(Chasy_idut) {d=new Date(); document.f.c.value= d.gethours()+':'+ d.getMinutes()+':'+ d.getSeconds()} setTimeout("myclock();",500)} function FlipFlag() {Chasy_idut=!Chasy_idut; document.f.b.value=(Chasy_idut)? 'Остановить': 'Запустить'} </SCRIPT> <BODY onLoad="myclock();"> <FORM NAME=f> Текущее время:<INPUT NAME=c size=8> <INPUT TYPE=button name=b VALUE="Запустить" onClick="FlipFlag();"> </FORM>
Пример 4.2. Часы с использованием setTimeout()
Обратите внимание, что поток порождается (т.е. вызывается setTimeout()) всегда, даже в том случае, когда мы остановили показ часов. Если бы он создавался только при значении переменной Chasy_idut=true, то часы бы просто не запустились, так как в самом начале исполнения скрипта мы установили var Chasy_idut=false. Но даже если бы мы установили в начале var Chasy_idut=true, то часы бы запустились при загрузке страницы, а после остановки поток бы исчез, и при последующем нажатии кнопки "Запустить" часы продолжали бы стоять.
Метод clearTimeout()
Метод clearTimeout() позволяет уничтожить поток, вызванный методом setTimeout(). Очевидно, что его применение позволяет более эффективно распределять ресурсы вычислительной установки. Для того чтобы использовать этот метод в примере с часами, нам нужно модифицировать функции и форму:
<SCRIPT> var Chasy_idut=false; var potok; function StartClock() {d=new Date(); document.f.c.value= d.gethours()+':'+ d.getMinutes()+':'+ d.getSeconds(); potok=setTimeout('StartClock();',500); Chasy_idut=true} function StopClock() {clearTimeout(potok); Chasy_idut=false} </SCRIPT> <FORM NAME=f> Текущее время:<INPUT NAME=c size=8> <INPUT TYPE=button VALUE="Запустить" onClick="if(!Chasy_idut) StartClock();"> <INPUT TYPE=button VALUE="Остановить" onClick="if(Chasy_idut) StopClock();"> </FORM>
Пример 4.3. Часы с использованием setTimeout() и clearTimeout()
В данном примере для остановки часов используется метод clearTimeout(). При этом, чтобы не порождалось множество потоков, проверяется значение указателя на объект потока.
Методы setInterval() и clearInterval()
В предыдущих примерах для того, чтобы поток запускался снова и снова, мы помещали в функцию в качестве последнего оператора вызов метода setTimeout(). Однако в JavaScript для этих целей имеются специальные методы. Метод setInterval("код_JavaScript",time) выполняет код_JavaScript с периодом раз в time миллисекунд. Возвращаемое значение - ссылка на созданный поток. Чтобы остановить поток, необходимо вызвать метод clearInterval(поток).
События объекта window
Остановимся вкратце на событиях, связанных с объектом window. Обработчики этих событий обычно помещают как атрибут контейнера .
<BODY onLoad="alert('Документ полностью загружен.');">
<BODY onUnload="myWin.close();">
<SCRIPT> function ff() {alert('Произошла ошибка. Свяжитесь с Web-мастером.');} window.onerror=ff; Alert('Привет') </SCRIPT>
<BODY onFocus="alert('Спасибо, что снова вернулись!');">
Переменные как свойства окна
Глобальные переменные на самом деле являются свойствами объекта window. В следующем примере мы открываем окно с идентификатором wid, заводим в нем глобальную переменную t и затем пользуемся ею в окне-родителе, ссылаясь на нее как wid.t:
<SCRIPT> wid=window.open('','','width=750,height=100,status=yes'); wid.document.open(); R=wid.document.write; R('<SCRIPT>var t;<\/SCRIPT>'); R('<H1>Новое окно</H1>'); wid.document.close() </SCRIPT> <A HREF="javascript: wid.t=window.prompt('Новое состояние:',''); wid.status=wid.t; wid.focus(); void(0);" >Изменим значение переменной t в новом окне</A>
Пример 4.4. Изменение переменной открытого окна
Обратите внимание на нюанс: внутри скрипта мы написали <\/SCRIPT>. Комбинация "\/" выдает на выходе "/". Сделали мы это для того, чтобы браузер (точнее, его HTML-парсер) не воспринял бы </SCRIPT> как завершающий тэг нашего (внешнего) скрипта. Подробнее этот аспект обсуждался во вводной лекции. Также обратите внимание на алиас (синоним) R, который мы дали методу wid.document.write, чтобы иметь возможность кратко вызывать его как R(...).
Аналогичным образом (с приставкой wid, указывающей на объект окна) можно обращаться ко всем элементам, находящимся в открытом нами окне, например, к формам. В качестве примера рассмотрим изменение поля ввода в окне-потомке из окна-предка. Создадим дочернее окно с помощью функции okno(), в нем создадим форму, а затем обратимся к полю этой формы из окна-предка:
<SCRIPT> var wid;//Объявляем глобальную переменную function okno() {wid=window.open('','okoshko','width=500,height=200'); wid.document.open(); R=wid.document.write; R('<H1>Меняем текст в окне-потомке:</H1>'); R('<FORM NAME=f><INPUT SIZE=40 NAME=t VALUE=Текст>'); R('</FORM>'); wid.document.close()} </SCRIPT> <INPUT TYPE=button VALUE="Открыть окно примера" onClick="okno()"> <INPUT TYPE=button VALUE="Написать текущее время в поле ввода" onClick="window.wid.document.f.t.value=new Date();window.wid.focus();">
Пример 4.5. Изменение поля статуса в открытом окне
Открывая окно-потомок, мы поместили в переменную wid указатель на окно: wid=window.open(...);. Теперь мы можем использовать wid как идентификатор объекта класса Window. Вызов метода window.wid.focus() в нашем случае обязателен, поскольку при нажатии на кнопку "Написать текущее время в поле ввода" происходит передача фокуса в родительское окно (которое может заслонять вновь открытое окно, так что изменения, происходящие в окне-потомке, не будут видны пользователю). Для того, чтобы увидеть изменения, мы должны передать фокус в окно-потомок.
Переменная wid должна быть глобальной, т.е. определена за пределами каких-либо функций (как сделано в нашем примере). В этом случае она становится свойством объекта window, поэтому мы обращаемся к ней в обработчике onClick посредством window.wid. Если бы мы поместили ее внутри описания функции okno(), написав var wid=window.open(...), то мы не смогли бы к ней обратиться из обработчика события onClick, находящегося вне функции okno().
Объект document
Объект document является важнейшим свойством объекта window (т.е. полностью к нему нужно обращаться как window.document). Все элементы HTML-разметки, присутствующие на web-странице, - текст, абзацы, гиперссылки, картинки, списки, таблицы, формы и т.д. - являются свойствами объекта document. Можно сказать, что технология DHTML (Dynamic HTML), т.е. динамическое изменение содержимого web-страницы, заключается именно в работе со свойствами, методами и событиями объекта document (не считая работы с окнами и фреймами).
Свойства | Методы | События |
---|---|---|
URL domain title lastModified referrer cookie linkColor alinkColor vlinkColor |
open() close() write() writeln() getSelection() getElementById() getElementsByName() getElementsByTagName() |
Load Unload Click DblClick MouseDown MouseUp KeyDown KeyUp Keypress |
Помимо перечисленных в этой таблице свойств, объект document имеет свойства, являющиеся коллекциями (форм, картинок, ссылок и т.п.); таблица 3.1 содержит их описание. Кроме того, можно формировать требуемые коллекции "на лету" с помощью указанных выше методов. Так, document.getElementsByTagName('P') есть коллекция всех HTML-элементов (точнее, соответствующих им объектов) вида <P>, т.е. абзацев. Аналогично, document.getElementsByName('important') выдаст коллекцию (объектов) HTML-элементов любых типов, у которых был задан атрибут NAME="important". Наконец, document.getElementById('id5') выдаст тот HTML-элемент (если их несколько, то первый), у которого был задан атрибут ID="id5".
С одним методом мы уже часто работали: document.write() - он пишет в текущий HTML-документ. Его модификация document.writeln() делает то же самое, но дополнительно добавляет в конце символ новой строки; это удобно, если потом требуется читать сгенерированный HTML-документ глазами. Если запись идет в HTML-документ нового окна, открытого с помощью window.open(), то перед записью в него нужно открыть поток на запись с помощью метода document.open(), а по окончании записи закрыть поток методом document.close(). После выполнения последнего действия произойдет событие Load (и вызовется соответствующий обработчик события onLoad) у документа, а затем у окна.
События объекта document аналогичны одноименным событиям объекта window (только у document они происходят раньше), либо их смысл понятен из их названия, поэтому мы не будем детально их разбирать.
Остановимся вкратце на свойствах объекта document. Свойства linkColor, alinkColor и vlinkColor задают цвет гиперссылок - непосещенных, активных и посещенных, соответственно. Свойство URL хранит адрес текущего документа (т.е. строковый литерал, равный window.location.href, если страница состоит из единственного документа, а не является набором фреймов). Свойство domain выдает домен (оно аналогично window.location.hostname). Свойство title выдает заголовок страницы (указанный в контейнере TITLE), lastModified указывает на дату и время последней модификации файла, в котором содержится данный HTML-документ (без учета времени модификации внешних файлов - стилевых, скриптов и т.п.). Свойство referrer выдает адрес страницы, с которой пользователь пришел на данную web-страницу, кликнув по гиперссылке. Наконец, свойству cookie посвящен целый раздел в лекции 8.
Фреймы (Frames)
Фреймы - это несколько видоизмененные окна. Отличаются они от обычных окон тем, что размещаются внутри них. У фрейма не может быть ни панели инструментов, ни меню, как в обычном окне. В качестве поля статуса фрейм использует поле статуса окна, в котором он размещен. Существует и ряд других отличий.
Если окно имеет фреймовую структуру (т.е. вместо контейнера в нем присутствует контейнер FRAMESET со вложенными в него контейнерами FRAME и быть может другими контейнерами FRAMESET), то объект window соответствует внешнему контейнеру FRAMESET, а с каждым вложенным контейнером FRAME ассоциирован свой собственный объект класса Window.
Каждому окну или фрейму создатель страницы может дать имя - с помощью атрибута NAME контейнера FRAME, либо вторым аргументом метода window.open(). Используется оно в качестве значения атрибута TARGET контейнеров A и FORM, чтобы открыть ссылку или отобразить результаты работы формы в определенном окне или фрейме. Есть несколько зарезервированных имен окон: _self (имя текущего окна или фрейма, где исполняется скрипт), _blank (новое окно), _parent (окно-родитель для данного фрейма), _top (самый старший предок данного фрейма, т.е. окно браузера, частью которого является данный фрейм). Иерархия фреймов, обсуждаемая ниже, как раз и задает, какие окна или фреймы являются родителями для других фреймов.
У каждого объекта класса Window, будь то окно или фрейм, есть также ссылка на соответствующий объект. Как мы знаем, ссылкой на объект текущего окна, в котором исполняется скрипт, является window; кроме того, на него же ссылается свойство self объекта window (а также свойство window объекта window - есть и такое!). Ссылку на объект окна, открываемого методом window.open(), выдает сам этот метод. Ссылка на объект-фрейм совпадает с его именем, заданным с помощью атрибута NAME контейнера FRAME. Наконец, у объектов-фреймов есть специальные свойства, дающие ссылки на родительский фрейм (window.parent) и на окно браузера, частью которого является данный фрейм (window.top).
Таким образом, для того, чтобы правильно обращаться к нужным фреймам, нам нужно знать лишь их иерархию, т.е. взаимное подчинение (какой фрейм для какого является родителем). Это мы сейчас и обсудим.
Иерархия и именование фреймов
Рассмотрим сначала простой пример. Разделим экран на 2 вертикальные колонки:
<TITLE>Левый и правый</TITLE> <FRAMESET COLS="50%,*"> <FRAME NAME=leftframe SRC=left.htm> <FRAME NAME=rightframe SRC=right.htm> </FRAMESET>
Пример 4.6. 2 фрейма
Рис.4.3. Окно с 2 вертикальными фреймами
Иерархия фреймов здесь получается следующая:
Из основного окна (из скрипта, который можно было поместить в контейнер) обратиться к левому фрейму можно с помощью window.leftframe, к правому - window.rightframe. Из каждого фрейма обратиться к основному окну можно как window.parent либо window.top (что в данном случае равносильно) или даже просто parent и top (так как приставку window можно опускать). Наконец, из левого фрейма обратиться к правому фрейму можно как parent.rightframe или top.rightframe.
Усложним пример: разобьем правый фрейм на 2 по горизонтали:
<TITLE>Левый, верх и низ</TITLE> <FRAMESET COLS="50%,*"> <FRAME NAME=leftframe SRC=left.htm> <FRAMESET ROWS="50%,*"> <FRAME NAME=topframe SRC=top.htm> <FRAME NAME=botframe SRC=bottom.htm> </FRAMESET> </FRAMESET>
Пример 4.7. 3 фрейма
Рис.4.4. Правый фрейм разбит на 2 по горизонтали
Фрейма с именем rightframe теперь не существует. Более того, все три фрейма непосредственно подчинены главному окну, т.е. иерархия выглядит следующим образом:
Следовательно, мы можем поместить в контейнер следующий скрипт, устанавливающий цвет фона для всех трех фреймов: (открыть)
<SCRIPT> window.onload=f; function f() {window.leftframe.document.bgColor='blue'; window.topframe.document.bgColor='red'; window.botframe.document.bgColor='green'} </SCRIPT>
Для того чтобы фрейм rightframe все же появился в иерархии и ему подчинялись 2 правых фрейма, нужно свести оба наших примера в один. Это значит, что во фрейм rightframe мы должны загрузить отдельный фреймовый документ.
Основной документ | Документ в правом фрейме (right.htm) |
---|---|
<FRAMESET COLS="50%,*"> <FRAME NAME=leftframe SRC=left.htm> <FRAME NAME=rightframe SRC=right.htm> </FRAMESET> |
<FRAMESET ROWS="50%,*"> <FRAME NAME=topframe SRC=top.htm> <FRAME NAME=botframe SRC=bottom.htm> </FRAMESET> |
В этом случае иерархия фреймов будет выглядеть иначе:
Теперь чтобы из главного окна обратиться ко всем трем фреймам и установить в них те же цвета фона, следует писать:
window.leftframe.document.bgColor='blue'; window.rightframe.topframe.document.bgColor='red'; window.rightframe.botframe.document.bgColor='green';
Таким образом, визуально на Web-странице мы получили тот же результат, что и с тремя фреймами, подчиненными одному старшему окну (см.пример 4.7). Однако этот вариант более гибкий: он позволяет работать независимо с фреймом rightframe в отдельном файле.
Коллекция фреймов
Выше мы обращались к фрейму по его имени. Однако, если имя не известно (или не задано), либо если нужно обратиться ко всем дочерним фреймам по очереди, то более удобным будет обращение через коллекцию фреймов frames[], которая является свойством объекта window.
В качестве иллюстрации предположим, что в примере из 2 фреймов (пример 4.6) правый фрейм содержит несколько изображений, и нам требуется поменять адрес (значение атрибута SRC) третьего изображения с помощью скрипта, находящегося в левом фрейме. Правый фрейм - 2-й, значит, его номер 1; третье изображение имеет номер 2. Поэтому, это можно сделать следующими способами:
top.frames[1].document.images[2].src='pic.gif'; top.frames['rightframe'].document.images[2].src='pic.gif'; top.frames.rightframe.document.images[2].src='pic.gif'; top.rightframe.document.images[2].src='pic.gif';
Передача данных во фрейм
Обычной задачей при разработке типового Web-узла является загрузка результатов исполнения CGI-скрипта во фрейм, отличный от фрейма, в котором вводятся данные для этого скрипта. Если путь загрузки результатов фиксированный, то можно просто использовать атрибут TARGET формы. Сложнее, если результат работы должен быть загружен в разные фреймы (например, в зависимости от выбранной кнопки).
Применим полученные нами знания для решения этой задачи. Сначала заготовим следующие файлы. Основной файл, например, index.htm, содержит левый фрейм, в котором будет находиться форма, и правый фрейм, разбитый на 2 подфрейма (верхний и нижний). Файл left.htm содержит форму, в которой пользователю предоставляется возможность выбрать верхний или нижний фрейм и нажать кнопку "Загрузить". Файл right.htm содержит простой текст; он будет загружаться в верхний или нижний фрейм, в зависимости от действий пользователя.
Основной файл с тремя фреймами | Файл с формой left.htm в левом фрейме | Файл right.htm |
---|---|---|
<TITLE>Три фрейма</TITLE> <FRAMESET COLS="50%,*"> <FRAME NAME=leftframe SRC=left.htm> <FRAMESET ROWS="50%,*"> <FRAME NAME=topframe SRC=""> <FRAME NAME=botframe SRC=""> </FRAMESET> </FRAMESET> |
<SCRIPT SRC="loadframe.js"></SCRIPT> <FORM MEthOD=post ACTION=right.htm NAME=f onSubmit="return load();"> <SELECT NAME=s> <OPTION>верхний</OPTION> <OPTION>нижний</OPTION> </SELECT> <INPUT TYPE=submit VALUE="Загрузить"> </FORM> |
Этот документ мы загружаем при выборе фрейма из списка |
Для того, чтобы пример заработал, остается в файле loadframe.js описать функцию load(). Функция должна делать так, чтобы в зависимости от выбора пользователем значения селектора "верхний" или "нижний" файл right.htm загружался бы либо в правый верхний, либо в правый нижний фрейм. С этой целью в файле left.htm у формы не был указан целевой фрейм (атрибут TARGET).
Нашу задачу динамического выбора фрейма можно решать по-разному. Более изящный способ - переназначать "на лету" свойство target, с него мы и начнем.
function load() {if(document.f.s.selectedIndex==0) {document.f.target="topframe"; top.frames[2].document.open(); top.frames[2].document.close()} else {document.f.target="botframe"; top.frames[1].document.open(); top.frames[1].document.close()} return true}
Пример 4.8. Файл loadframe.js: переназначение target на лету
Функция load() всегда возвращает true, а поскольку она вызывается из обработчика события onSubmit, это означает, что всегда будет происходить отправка формы (событие Submit), т.е. загрузка страницы right.htm, указанной в атрибуте ACTION данной формы. Обратите внимание также на следующие строки в функции load():
top.frames[1].document.open(); top.frames[1].document.close();
Смысл их таков: когда пользователь выбирает значение верхний или нижний в форме, то файл right.htm загружается в соответствующий фрейм, а оставшийся фрейм открывается на запись (методом ...document.open(), при этом всё его содержимое очищается) и закрывается (методом ...document.close()), тем самым фрейм остаётся пустым (без текста).
Теперь рассмотрим 2-й подход - открытие окна с именем, совпадающим с именем фрейма topframe или botframe. Его идея состоит в том, что при попытке открыть окно с именем существующего окна новое окно не открывается, а используется уже открытое. Фрейм - это тоже окно, поэтому на него данное правило распространяется. Функция, реализующая такое поведение, приведена ниже:
function load() {if(document.f.s.selectedIndex==0) {window.open("right.htm","topframe"); top.frames[2].document.open(); top.frames[2].document.close()}else{window.open("right.htm","botframe"); top.frames[1].document.open(); top.frames[1].document.close()} return false}
Пример 4.9. Файл loadframe.js: использование window.open()
В этом подходе функция load() всегда возвращает false. Это необходимо, чтобы отменить отправку данных формы: ведь после того, как мы вызвали window.open(), в отправке данных формы, т.е. загрузке файла right.htm, уже нет надобности.