|
Другими словами, мы добавим немного эффектов. Но сначала я бы хотел сделать небольшое лирическое отступление:
На самом деле, при создании выпадающего меню мы будем работать с DHTML (Dinamic Hypertext Markup Language). Который представляет из себя нечто иное как HTML четвёртой версии с расширенным JavaScript. Основной проблемой,мешающей повсеместному внедрению этой технологии,является несовместимость браузеров. К счастью, на сегодняшний день 2 популярных браузера Netscape Navigator (N.S. 6.0 и выше) и Internet Explorer (I.E. 4.0 и выше) являются, если можно так выразиться, более менее совместимыми (далеко не на все 100). Для них, а также для N.S. 4.0. и написаны сценарии прилагаемые к этой статье.
Что же такое слой? Слой - это некий прямоугольный элемент,содержащий в себе разметку HTML. Сами слои обозначаются следующими тэгами: <div>, <span>, <layer>, <ilayer> и имеют следующие параметры стиля (style):
position - определяет точку отсчёта координат. Может принимать следующие значения:
absolute - координаты отсчитываются относительно верхнего левого угла документа;
relative - от верхнего левого угла слоя содержащий описываемый слой;
top - определяет Y слоя;
left - определяет X слоя;
z-index - определяет уровень слоя. Данный параметр используется при наложении слоёв друг на друга (перекрытии). Он указывает браузеру какой слой находится выше (рекомендуется использовать значения z-index>=0).
visibility - видимость слоя:
visible - слой виден;
hidden - слой скрыт.
А это HTML код одного из слоя-подменю (в нашем примере их 3):
<DIV ID="submenu1" STYLE="FONT-FAMILY: Verdana, Arial, Helvetica, sans-serif;LEFT: -1000px; VISIBILITY: hidden;POSITION: absolute;TOP: -1000px;" onMouseOut="hidemenu(true)" onMouseOver="cancelhide()">
<table cellpadding=1 cellspacing=0 BORDER=1 width=150>
<tr>
<td width=80><a href="">SubMenu1_1</a></td>
</tr>
<tr>
<td><a href="">SubMenu1_2</a></td>
</tr>
<tr>
<td><a href="">SubMenu1_3</a></td>
</tr>
<tr>
<td><a href="">SubMenu1_4</a></td>
</tr>
</table>
</DIV>
Слоями можно манипулировать,изменяя их параметры с помощью JavaScript. Например, чтобы заставить браузер отобразить невидимый слой,мы можем использовать следующий скрипт:
Для IE 4:
document.all["layername"].visibility=’visible’;
Для NS 4:
document.layers["layername"].visibility="visible";
Для IE 5 и NS 6:
layer= document.getElementById(“layername”);
layer.style.display = "";
Оказывается,можно не только отображать весь слой целиком, но и его часть. С помощью так называемой области отсечения (поддерживается в IE и в NS начиная с версии 4). Вот таким образом:
Для IE 5 и NS 6:
layer = document.getElementById("layername");
layer.style.clip = "rect(top right bottom left)";
(Где top, right, bottom, left - координаты области отсечения).
Для IE 4:
document.all.layername.style.clip = "rect(top right bottom left)";
Для NS 4:
document.layers.layername.clip.top = top;
document.layers.layername.clip.right = right;
document.layers.layername.clip.bottom = bottom;
document.layers.layername.clip.left = left;
Но и это ещё не всё! Вы также можете управлять прозрачностью слоёв с помощью JS:
В IE:
document.all.layername.style.filter="alpha(opacity=75)";
В NS 6:
layer = document.getElementById("layername");
layer.style.MozOpacity = 75/100;
Ну а теперь, когда мы знаем что такое слои и с чем их едят,можно приступить к модификации сценариев для работы меню. Ведь если в предыдущей статье этого цикла мы писали меню, которое раскрывается мгновенно, то здесь нам нужно добавить эффекты при его открытии и закрытии. А это будет стоить нам нескольких десятков дополнительных строк кода, и ничего здесь не поделаешь. Поверьте мне, результат того стоит (см. ниже) !!! ;)
<Script Language="JavaScript">
var mstatus=true;
//mstatus - определяет раскрывается(true) или закрывается(false) меню
var timer1=false;
// сюда будет записываться задержка закрытия
var mstep=3;
// кол-во пикселей, на которые будет передвигаться меню за 1 итерацию
var cm=null;
// здесь будет запоминаться последний активный слой
var hide_delay=500;
// задержка перед тем, как активный слой станет невидимым
var tstat=0;
// имеются ли видимые слои (0 - нет, 1 - да)
// Определяем браузер пользователя
isNS4 = (document.layers) ? true : false;
isIE4 = (document.all && !document.getElementById) ? true : false;
isIE5 = (document.all && document.getElementById) ? true : false;
isNS6 = (!document.all && document.getElementById) ? true : false;
// Функция, отображающая и скрывающая слои
// Вход:
// objElement - идентификатор(id) слоя;
// bolVisible - булева переменная:
// true - отобразить слой;
// false - скрыть слой.
// Выход:
// 1
// P.S: В зависимости от типа браузера
// сценарий для манипуляции с видимостью слоёв
// несколько различается.
function switchDiv(objElement,bolVisible){
if(isNS4||isIE4){
if(!bolVisible) {
objElement.visibility ="hidden"
} else {
objElement.visibility ="visible"
}
} else if (isIE5 || isNS6) {
if(!bolVisible){
objElement.style.display = "none";
} else {
objElement.style.display = "";
}
}
return 1;
}
// Функция, возвращающая значение указанного ей
// свойства объекта (не обязательно слоя).
// Вход:
// el - идентификатор элемента;
// sProp - свойство (left,top...)
// Выход:
// Значение какого-нибудь свойства объекта.
function getPos(el,sProp) {
var iPos = 0;
while (el!=null) {
iPos+=el["offset" + sProp]
el = el.offsetParent
}
return iPos
}
// Функция выдаёт объект с указанным
// ей названием.
// Вход:
// myid - название объекта
// Выход: объект.
function getelementbyid(myid) {
if (isNS4){
objElement = document.layers[myid];
}else if (isIE4) {
objElement = document.all[myid];
}else if (isIE5 || isNS6) {
objElement = document.getElementById(myid);
}
return(objElement);
}
// Функция отображающая|скрывающая
// слои.
// Данная Функция не меняет координаты слоёв,
// не делает их прозрачными, а вызывает функцию movefx,
// которая этим занимается.
// Вход:
// el - яйчейка таблицы на которой
// находится указатель;
// m - наименование слоя, который надо
// отобразить под этой яйчейкой.
function show(el,m) {
if (m!=null) {
m=getelementbyid(m);
}
// получаем элемент в m
if ((el==null) && (cm)) {
mstatus=false;
movefx()
// закрываем меню через movefx
} else if ((m!=cm) && (m)) {
if (cm!=null) switchDiv(cm,false);
// пользователь перешёл на другой пункт основного меню
// немедлено сделать невидимым предыдущий (cm) видимый в данный момент слой.
switchDiv(m,true); // сделать видимым слой m
fxel=el;
fxm=m;
fxrect=0; // текущая высота области отсечения (см. ниже)
// запоминаем значения в глобальных переменных
// для использования в дальнейшем
mstatus=true; // будем открывать меню с помощью movefx
movefx()
}
if (m) cm=m;
// запоминаем значение m в cm
if (tstat==1) {
clearTimeout(timer1);
tstat=0
// если таймер timer1 запущен, останавливаем его
}
}
// Функция, "закрывающая" меню.
// Функция принимает на вход b типа boolean
// при true закрывает меню учитывая задержку hide_delay;
// при false (или каком-либо другом значении кроме true)
// закрывает меню немедленно
// и возвращает 1.
function hidemenu(b) {
if (b) {
tstat=1;
timer1=setTimeout("show(null)",hide_delay);
} else {
tstat=0;
show(null);
}
}
// Функция, останавливающая таймер, запущенный
// прошлой функцией. Таким образом,
// меню не пропадает.
// Функция ничего не принимает на вход
// и возвращает 1.
function cancelhide() {
if (!mstatus) {
mstatus=1;
// если меню закрывалось, открываем его вновь
}
tstat=0;
clearTimeout(timer1);
// останавливаем таймер
}
// Функция, отвечающая за эффектное выпадение меню.
// Ничего не принимает на вход
// Возвращает 1.
function movefx() {
if ((mstatus) && (fxrect>fxm.offsetHeight)) {
fxrect=fxm.offsetHeight;
return 1;
// Если меню открывается и высота области отсечения больше
// высоты самого слоя, то делаем высоту области равной высоте слоя
// и выходим из функции.
}
if ((!mstatus) && (fxrect<0)) {
fxrect=0;
switchDiv(fxm,false);
mstatus=true;
cm=null;
return 1;
// Если меню закрывается и область отсечения меньше 0
// (признак того, что меню полностью закрылось)
// делаем область = 0
// делаем слой невидимым
// ставим mstatus=true (чтобы при следующем вызове show
// меню снова открывалось)
// выходим из функции (возвращая 1)
}
if ((isIE5)||(isIE4)||(isNS4)||(isNS6)) {
if (!isNS4) {
fxm.style.left = getPos(fxel,"Left")+"px";
fxm.style.clip='rect(' + (fxm.offsetHeight-fxrect) +
' '+ fxm.offsetWidth + ' ' + fxm.offsetHeight +' '+ 0 +')';
fxm.style.top = getPos(fxel,"Top")+(fxel.offsetHeight-fxm.offsetHeight+fxrect+2)+"px";
} else {
fxm.left=getPos(fxel,"Left");
fxm.clip.top=fxm.offsetHeight-fxrect;
fxm.clip.bottom=fxm.offsetHeight;
fxm.clip.left=0;
fxm.clip.right=fxm.offsetWidth;
fxm.top=getPos(fxel,"Top")+(fxel.offsetHeight-fxm.offsetHeight+fxrect+2);
}
// это всё описано вначале данной статьи :)
if (mstatus) {
fxrect=fxrect+mstep;
setTimeout('movefx()',1);
// Если меню открывается,
// прибавляем к высоте области отсечения значение mstep;
// запускаем таймер для повторного выполнения movefx через 1 м.сек.
} else {
fxrect=fxrect-mstep;
setTimeout('movefx()',1);
// Иначе (меню закрывается), отнимаем от высоты области отсечения
// значение mstep.
}
return 1;
} else {
if (mstatus) {
fxm.style.left =getPos(fxel,"Left")+"px";
fxm.style.top = (getPos(fxel,"Top")+ fxel.offsetHeight) +"px";
} else {
switchDiv(fxm,false);
cm=null;
mstatus=true;
}
return 1
}
}
</Script>
HTML код таблицы - основного меню:
<TABLE WIDTH=450 BORDER=1 onMouseOut="hidemenu(true)" onMouseOver="cancelhide()">
<TR>
<TD width=150 align="center" onMouseOver="show(this,'submenu1')"><a href="">Menu 1</a></TD>
<TD Width=150 align="center" onMouseOver="show(this,'submenu2')"><a href="">Menu 2</a></TD>
<TD width=150 align="center" onMouseOver="show(this,'submenu3')"><a href="">Menu 3</a></TD>
</TR>
</TABLE>
Попробуйте навести курсор на какой-либо пункт данного меню и смотрите, что будет:
Посмотреть пример в отдельном окне
Вы хотите чтобы меню не «ездило», а плавно появлялось? No problem =) Для этого нам придётся переписать всего одну функцию. Функцию movefx(). Теперь она будет выглядеть следующим образом:
function movefx() {
if ((mstatus) && (fxrect>100)) {
fxrect=100;
return 1;
}
if ((!mstatus) && (fxrect<0)) {
fxrect=0;
switchDiv(fxm,false);
mstatus=true;
cm=null;
return 1;
}
if ((isIE5)||(isIE4)||(isNS6)) {
fxm.style.top=getPos(fxel,"Top")+(fxel.offsetHeight+2)+'px';
fxm.style.left=getPos(fxel,"Left")+'px';
if (isNS6) {
fxm.style.MozOpacity = fxrect/100;
} else {
fxm.style.filter = 'alpha(opacity='+fxrect+')';
}
if (mstatus) {
fxrect=fxrect+mstep;
setTimeout('movefx()',1);
} else {
fxrect=fxrect-mstep;
setTimeout('movefx()',1);
}
return 1;
} else {
if (mstatus) {
fxm.style.left =getPos(fxel,"Left")+"px";
fxm.style.top = (getPos(fxel,"Top")+ fxel.offsetHeight) +"px";
} else {
switchDiv(fxm,false);
cm=null;
mstatus=true;
}
return 1
}
}
Подставив эту функцию вместо приведённой в 1-ом листинге, мы получим вот такую симпатичную менюшку:
Посмотреть пример в отдельном окне
Конечно здесь были рассмотрены далеко не все возможные варианты. Но я уверен, что используя упомянутые приёмы, вам будет по плечу создать любое выпадающее меню. Вы можете также свободно использовать все описанные в этой статье сценарии на своих веб-сайтах, изменять их, только одна просьба, если не жалко, в этом случае разместите ссылку на www.abc-it.lv на какой-нибудь странице вашего сайта! =)
До новых встреч!
Перейти к рубрике --> JavaScript |