Рассмотрим
более сложную операцию -
свертывание и развертывание слоя.
Будем выполнять ее по горизонтали.
По вертикали эта операция
выполняется аналогично. Для ее
выполнения нам нужно знать ширину
слоя. Если мы хотим свернуть слой,
никаких предварительных действий
предпринимать не надо, но если мы
хотим его развернуть, то нужно
установить область обреза с левым и
правым краями, равными половине
ширины слоя. Это можно установить
при определении слоя, или в начале
программы JavaScript. При этом надо не
забыть предварительно спрятать
слой для устранения мелькания.
Создадим
функцию свертки/развертки:
function curtainWidth(layerName,xinc,inctime,stopwidth)
второй
параметр определяет величину
прироста/уменьшения ширины, третий -
задержку, а четвертый - конечную
ширину. Если мы развертываем слой,
то конечная ширина должна быть
равна ширине слоя, если свертываем,
то нулю.
Первым
делом изменим левый и правый край
области обреза:
eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.clip.left += -(xinc/2)');
eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.clip.right += (xinc/2)');
Если
мы перестарались, то подправим
ширину обреза:
if (eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.clip.width < 0')){lyr.clip.width = 0}
Теперь
проверим, не достигли ли мы
конечного условия:
if (((xinc < 0) && (eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.clip.width > stopwidth'))) ||
((xinc > 0) && (eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.clip.width < stopwidth'))))
Если
нет, то рекурсивно вызовем функцию:
setTimeout('curtainWidth("'+layerName+'",'+xinc+','+inctime+','+stopwidth+')',inctime);
Вот,
что у нас получилось:
function curtainWidth(layerName,xinc,inctime,stopwidth) {
eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.clip.left += -(xinc/2)');
eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.clip.right += (xinc/2)');
if (eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.clip.width < 0')){lyr.clip.width = 0}
if (((xinc < 0) && (eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.clip.width > stopwidth'))) ||
((xinc > 0) && (eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.clip.width < stopwidth')))) {
setTimeout('curtainWidth("'+layerName+'",'+xinc+','+inctime+','+stopwidth+')',inctime);
Движение
слоя по окну.
Для
примера рассмотрим движение
сверху вниз. Затем по аналогии Вы
сможете организовывать
перемещение в других направлениях
или по более сложным траекториям.
Для того, чтобы осуществить
перемещение нужно знать четыре
значения: текущее положение, место
остановки, шаг перемещения, время
задержки. Мы ограничимся двумя
переменными, а шаг и задержку
зададим константами.
Создадим
функцию перемещения
function moveLayerDown(layerName,currTop,topstop)
В ней
сначала проверим, не достиг ли слой
конечной точки
if (eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.top != topstop'))
если
это не произошло, сдвинем слой вниз
currTop+=2;
eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.top = currTop');
и
рекурсивно вызовем функцию
setTimeout('moveLayerDown("'+layerName+'",'+currTop+','+topstop+')',50);
Вот,
что у нас получилось:
function moveLayerDown(layerName,currTop,topstop){
if (eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.top != topstop')){
currTop+=2;
eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.top = currTop');
setTimeout('moveLayerDown("'+layerName+'",'+currTop+','+topstop+')',50);
}
}
Теперь
давайте для разминки напишем код,
который прячет указанный нами слой.
Создадим функцию hideLayer с параметром,
содержащим имя слоя, несколько
изменив приведенный выше eval(...):
function hideLayer(layerName){
eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.visibility="hidden"');
}
По
аналогии с ней создается и функция
showLayer:
function showLayer(layerName){
eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.visibility="visible"');
}
Пример.
Предзагрузка изображений для
правильного их показа.
Создадим
два слоя. Уже извесное нам сообщение
о загрузке (им может быть какая-нибудь
новость или цитата).
<style type="text/css">
#loading {POSITION: absolute; TOP:0; LEFT:0; Z-INDEX: 80000; WIDTH: 100%; HEIGHT: 100%;}
</style>
<div id="loading">
<table width="100%" height="100%">
<tr><td align="center" valign="middle">
Подождите пожалуйста...
</td></tr>
</table>
</div>
и
невидимый рабочий слой
<style type="text/css">
#logo {POSITION: absolute; TOP:50; LEFT:150; VISIBILITY: hidden; Z-INDEX: 84000;
WIDTH: 360px; HEIGHT: 280px;}
</style>
<div id="logo">
<img src="../images/biglogo.gif" width=359 height=279 border=0>
</div>
Теперь
в тэге body вызовем функцию прятания
слоя loading и показа слоя logong>
<body onload="init();hideLayer('loading');showLayer('logo');">
В
прошлом уроке мы написали функции
для прятания и показа слоя. Вот они:
function hideLayer(layerName){
eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.visibility="hidden"');
}
function showLayer(layerName){
eval(layerRef+'["'+layerName+'"]'+styleSwitch+'.visibility="visible"');
}
Воспользуемся
ими для реализации нашего примера.
Предположим, что у нас есть некое
меню. Мы хотим, чтобы при выборе
курсором мыши определенного пункта,
он подсвечивался вокруг (или
изменялся другим образом). Создадим
две картинки. Сам пункт меню и его
подсветку (В зависимости от способа
подсветки скрипт пишется немного по-разному,
он будет немного проще, если
подсвечивать не сверху, как у меня, а
снизу).
Создадим
два слоя. Один видимый с пунктом
меню, другой невидимый с подсветкой.
<style type="text/css">
#button1 {POSITION: absolute; Z-INDEX: 10; LEFT: 150; TOP: 60; WIDTH: 423; HEIGHT: 45}
#highlight1 {POSITION: absolute; Z-INDEX: 15; VISIBILITY: hidden; LEFT: 150; TOP: 60;
WIDTH: 423; HEIGHT: 45}
</style>
<div id="button1">
<a href="wd.html"><img src="wd.gif" width=189 height=43 border=0></a>
</div>
<div id="highlight1">
<a href="wd.html"><img src="wd-g.gif" width=189 height=43 border=0></a>
</div>
При
этом Z-INDEX у пункта меню должен быть
больше, чем у подсветки, если мы
подсвечиваем "снизу", и меньше,
если мы подсвечиваем "сверху" (наш
вариант).
Ну а
теперь воспользуемся событиями
onMouseOver и onMouseOut:
<a href="wd.html" onMouseOver="showLayer('highlight1')" onMouseOut="hideLayer('highlight1')">
<img src="wd.gif" width=189 height=43 border=0>
</a>
<a href="wd.html" onMouseOver="showLayer('highlight1')" onMouseOut="hideLayer('highlight1')">
<img src="wd-g.gif" width=189 height=43 border=0>
</a>
Если
используется подсветка "снизу",
ссылка у подсветки не нужна:
<a href="wd.html" onMouseOver="showLayer('highlight1')" onMouseOut="hideLayer('highlight1')">
<img src="wd.gif" width=189 height=43 border=0>
</a>
<img src="wd-g.gif" width=189 height=43 border=0>
Динамические
подсказки.
Вы
считаете, что Ваши пункты меню
недостаточно информативны? Вы
можете сделать так, чтобы при
наведении курсором на пункт меню в
определенном месте появлялась
подсказка.
Все,
что Вам для этого нужно, это для
каждого пункта меню создать
невидимый слой с подсказкой. При
этом все эти слои должны иметь
одинаковые позиционные параметры.
<style type="text/css">
#button1 {POSITION: absolute; Z-INDEX: 15; LEFT: 50; TOP: 60; WIDTH: 423; HEIGHT: 45}
#explain1 {POSITION: absolute; Z-INDEX: 15; VISIBILITY: hidden; LEFT: 200; TOP: 60;
WIDTH: 171; HEIGHT: 116}
</style>
<div id="button1">
<a href="mailto:untitled@r2.ru">Почта</a>
</div>
<div id="explain1">
Нажмите сюда, если Вы хотите послать письмо вебмастеру узла.
</div>
А
теперь, как и в предыдущем примере,
воспользуемся событиями onMouseOver и
onMouseOut:
<a href="mailto:untitled@r2.ru" onMouseOver="
showLayer('explain1')" onMouseOut="hideLayer('explain')">
Почта</a>
Различия
в IE и NC.
Internet
Exploter 4.0 (IE) и Netscape Communicator 4.0 (NC) по
разному интерпретируют HTML 4.0.
Поэтому прежде, чем
рассматривать принципы создания
Динамических HTML, рассмотрим
основные отличия этих браузеров
и как с ними бороться.
IE
представляет слои с помощью CSS и
тэга div, в то время как NC советует
использовать изобретенный им
тэг layer.
Например
для IE:
<head>
<style type="text/css">
#loading {POSITION: absolute; TOP:0; LEFT:0; Z-INDEX: 80000; WIDTH: 100%; HEIGHT: 100%;}
</style>
</head>
<body>
<div id="loading">
<table width="100%" height="100%">
<tr><td align="center" valign="middle">
Еще немного и из-за поворота выглянет то, к чему Вы так стремились...
</td></tr>
</table>
</div>
</body>
а
для NC:
<body>
<layer name="loading" left="0" top="0" z-index="80000" width="100%" height=100%">
<table width="100%" height="100%">
<tr><td align="center" valign="middle">
Еще немного и из-за поворота выглянет то, к чему Вы так стремились...
</td></tr>
</table>
</layer>
</body>
Тэг
layer ничем не отличается от CSS, за
исключением параметра source, с
помощью которого можно указать
внешний файл в котором хранится
содержимое слоя. Если Вы не
собираетесь поддерживать IE,
лучше выбрать синтаксис NC. Это
позволит строить сложные
документы и не повторять во всех
файлах стандартные слои, такие
как навигационнфя панель или
шапка страницы.
На
этом проблемы совместимости не
заканчиваются, а только
начинаются. Классы JavaScript в IE и NC
также реализованны по разному.
Например, чтобы показать слой в NC
надо сказать
document.layers["loading"].visibility="visible";
а
в IE:
document.all["loading"].style.visibility="visible";
Наш
урок носит обзорный характер,
поэтому мы не будем подробно
рассматривать все различия
реализации языка. Посмотрим
лучше, как решаются эти проблемы.
Как
с ними бороться
Слава
Netscape, в JavaScript есть пракрасная
функция eval(). Она параметр в
строку и интерпретирует ее так,
как-будто это строка программы.
Чтобы корректно спрятать слой
как в IE, так и в NC необходимо
написать следующую строку:
eval(layerRef+'["loading"]'+styleSwitch+'.visibility="visible"');
Теперь
все, что остается, это правильно
инициализовать переменные layerRef
и styleSwitch с помощью следующего
кода:
var layerRef="null", styleSwitch="null";
function init(){
if (navigator.appName == "Netscape") {
layerRef="document.layers";
styleSwitch="";
}else{
layerRef="document.all";
styleSwitch=".style";
}
}
вызвав
его в тэге body:
<body onload="init();">