Тема: JavaScript: Выпадающее меню
Пример простого выпадающего меню, можно настроить (переписать) под разные цели и задачи.
Меню работает в различных популярных браузерах (IE, Opera, FireFox).
<script language="javascript" type="text/javascript">
// Объявление глобальных переменных
var DOM = (typeof(document.getElementById)!='undefined');
var menu_div, _menu_a, div_i = null;
var js =
{
// addEvent - функция добавления события
/* Пример вызова: js.addEvent(document,'click',menu.check);
document - объект, которому назначается событие
click - название события
menu.check - имя функции (ВАЖНО: при использовании конструкции вроде js.addEvent(document,'click',function(){alert('сообщение')});) - это событие не удаляется!!!
*/
addEvent: function(el, evname, func){
if(el.attachEvent) // IE
el.attachEvent('on' + evname, func);
else if(el.addEventListener) // Gecko / W3C
el.addEventListener(evname, func, false);
else
el['on' + evname] = func;
},
// addEvent - функция удаления события
// Пример вызова: аналогично предыдущей функции (если необходимо удалить созданное событие - объект, имя события и имя функции должны совпадать)
removeEvent: function(el, evname, func){
if(el.detachEvent) // IE
el.detachEvent('on' + evname, func);
else if(el.removeEventListener) // Gecko / W3C
el.removeEventListener(evname, func, false);
else
el['on' + evname] = null;
},
/* Функция получения коодринат местоположения объекта на странице (el - объект, который анализируем)
функция возвращает ассоциативный массив со значениями положения объекта
Элементы массива:
'top' - расстояние в пикселях от верхнего края объекта до верхней точки документа
'left' - расстояние в пикселях от левого края объекта до левого края документа
'right' - расстояние в пикселях от нижнего края объекта до верхней точки документа
'bottom' - расстояние в пикселях от правого края объекта до левого края документа
*/
GetRealPos: function(el){
if(!el || !el.offsetParent)
return false;
var res=Array();
res['left'] = el.offsetLeft;
res['top'] = el.offsetTop;
var objParent = el.offsetParent;
while(objParent.tagName != 'BODY'){
res['left'] += objParent.offsetLeft;
res['top'] += objParent.offsetTop;
objParent = objParent.offsetParent;
}
res['right'] = res['left'] + el.offsetWidth;
res['bottom'] = res['top'] + el.offsetHeight;
return res;
}
}
// Объект выпадающего меню.
var menu =
{
// Метод show - вызывает меню
/* Получает параметры:
obj - необходимо передавать объект, относительно которого будет рисоваться меню
arr - массив определённой структуры:
в данном случае [['иконка','название пункта','ссылка'],['иконка','название пункта','ссылка']]
Пример вызова: onClick="menu.show(this,[['images/open.gif','Просмотр','/menu/#open'],['images/child.gif','Создать подкатегорию','/menu/#child']])"
*/
show: function(obj,arr){
if(div_i)div_i.className = 'menu_img';
menu_div = document.getElementById('menu');
_menu_a = document.getElementById('menu_a');
if(!arr){_menu_a.innerHTML = '';}
div_i = obj;
div_i.className = 'menu_img_hover';
pos = js.GetRealPos(obj);
_menu = menu_div;
_menu.style.top = pos.top + 9;
_menu.style.left = pos.left + 28;
if(arr){
_menu_a.innerHTML = menu.initFunc(arr);
}
else{return;}
_menu_pos = js.GetRealPos(_menu);
_menu.style.display = 'block';
js.addEvent(document,'click',menu.check);
js.addEvent(document,'keypress',menu.press);
},
hide: function(){
menu_div.style.display = 'none';
div_i.className = 'menu_img';
js.removeEvent(document, 'click', menu.check);
js.removeEvent(document, 'keypress', menu.press);
},
/* Метод initFunc - описывает правила для обработки массива и генерации html кода - описывается отображение пунктов меню
Этот метод не вызывается извне объекта menu
Получает параметры:
arr - массив определённой структуры:
в данном случае [['иконка','название пункта','ссылка'],['иконка','название пункта','ссылка']]
*/
initFunc: function(arr){
var html = '<table>';
for(i in arr){
im = "gray_pic.gif";
// Условие определяет какую картинку использовать, в зависимости от того, какой это пункт - первый или последний
if(arr.length!=1){
if(i==0){im = "s_menu_f.gif";}
else if(parseInt(i)+1==arr.length){im = "s_menu_l.gif";}
}
else{
im = "s_menu.gif";
}
// Здесь в переменную html добавлется по одной строке, соответственно здесь и настраивается вид пунктов меню
html += '<tr><td height="30"><img src="'+arr[i][0]+'" style="margin:0px 6px 7px 9px" alt=""><img src="images/'+im+'" class="s_im" alt=""></td><td valign="middle"><a class="menu_a" href="'+arr[i][2]+'">'+arr[i][1]+'</a></td></tr>';
}
html += '</table>';
return html;
},
// Метод press - скрывает меню при нажатии определённой клавиши, в данном случае - Esc
press: function(e){
if(!e) e = window.event;
if(!e) return;
if(e.keyCode == 27)
menu.hide();
},
// Метод check - проверяет - нужно ли скрывать меню или нет.
// В данном случае метод вызывается при кликании мышью, если координаты "клика" не совпадают с координатами меню и каких-либо объектов, то меню закрывается!
check: function(e){
if(!div_i)
return;
var x = e.clientX + document.body.scrollLeft;
var y = e.clientY + document.body.scrollTop;
/*menu_button region*/
if(div_i){
var pos = js.GetRealPos(div_i);
if(x >= pos['left'] && x <= pos['right'] && y >= pos['top'] && y <= pos['bottom'])
return;
}
/*menu region*/
if(_menu){
var pos = js.GetRealPos(_menu);
if(x >= pos['left'] && x <= pos['right'] && y >= pos['top'] && y <= pos['bottom'])
return;
}
menu.hide();
},
// Методы over и out - используются в данном случае для определения имени css класса, который нужно присвоить картинке, используется в частных случаях.
over: function(){
if(!div_i)
return;
div_i.className = 'menu_img_hover';
},
out: function(obj){
if(!obj)
return;
_menu = menu_div;
if(!_menu || obj!=div_i){obj.className = 'menu_img';}
else{
if(_menu.style.display != 'block'){obj.className = 'menu_img';}
}
}
}
</script>
Пример использования меню можно посмотреть здесь или во вложении этого поста.
Недостатки:
- Если не будет работать javascript - ссылки не будут видны (поэтому многие меню основаны на заранее описанных списках LI);
- Для создания многоуровнего меню необходимо дописывать методы, добавлять новые, т.е. скрипт не предусматривает изначально многоуровневые выпадающие меню.