Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Выпадающее меню (https://javascript.ru/forum/misc/4708-vypadayushhee-menyu.html)

theo_ 14.08.2009 17:58

Выпадающее меню
 
Всем привет, заранее извиняюсь за боянность темы :write:

Но хотелось бы самому во всем разобраться, а не использовать тупо чужие скрипты.

Есть горизонтальное меню
Код:

<div id="top_menu">
в нем расположены пункты меню, вот пример ссылки на главную страницу
Код:

<a class="top_menu_item" href="#" onmouseover="show_sub_menu()" onmouseout="hide_sub_menu()"><p class="top_menu_item_title">Главная</p></a>
ниже идет подменю, которое в обычном состоянии скрыто
Код:

<div id="top_submenu">
При наведении мышью на элемент верхнего меню, подменю появляется. Мышь отводим - исчезает. Как сделать так, чтобы подменю сразу не исчезало, а можно было выбрать его ссылки..

Заранее спасибо за помощь

B~Vladi 14.08.2009 18:01

Цитата:

Сообщение от theo_
Но хотелось бы самому во всем разобраться, а не использовать тупо чужие скрипты.

Мне уже нравицо:)

Выставляй таймер...

theo_ 14.08.2009 18:13

B~Vladi, спасибо большое

как я понял из гугля, надо использовать setTimeout и clearTimeout ?

zzz 14.08.2009 18:35

Да

zzz 14.08.2009 18:36

SetTimeout
Могу выслать вам свой код генерится полностью Явой легко изменяем и при наведении меняются параметры CSS

theo_ 14.08.2009 20:30

пришлось отвлечься :-E

zzz, спасибо, но мне хочется просто понять логику работы.

навел я мышкой на элемент меню, появилось подменю. мышку с пункта меню увожу, выполняю
Код:

timerID = setTimeout(hide(menu), 500);
только вот подменю убирается сразу, а не через 500мс

в чем может быть причина?

theo_ 14.08.2009 20:47

вообщем, что строка
Код:

timerID = setTimeout(hide(menu), 500);
что
Код:

hide(menu)
работают одинаково...

что я неправильно делаю?

theo_ 14.08.2009 21:05

вот такой вот скрипт получился:

Код:

var timerID = false;

function show_sub_menu()
{
  var menu = document.getElementById("top_submenu");
  menu.style.visibility = "visible";
  menu.onmouseover = "cancel_hide()";
  menu.onmouseout = "hide()";
}
function hide_sub_menu()
{
  var menu = document.getElementById("top_submenu");
  timerID = setTimeout(hide, 500);
}
function cancel_hide()
{
  var menu = document.getElementById("top_submenu");
  menu.style.visibility = "visible";
  clearTimeout(timerID);
}
function hide()
{
  var menu = document.getElementById("top_submenu");
  menu.style.visibility = "hidden";
}

не получается menu сделать глобальной переменной, в итоге еще и в функции ее каждый раз приходится определять

theo_ 14.08.2009 21:36

даже этот вот код работает неверно
Код:

var timerID = false;

function show_sub_menu()
{
  var menu = document.getElementById("top_submenu");
  menu.style.visibility = "visible";
}
function hide_sub_menu()
{
  var menu = document.getElementById("top_submenu");
  timerID = setTimeout(hide, 500);
}
function hide()
{
  var menu = document.getElementById("top_submenu");
  menu.style.visibility = "hidden";
}

смысл в нем, чтобы меню убиралось с задержкой 500мс

однако оно может убраться и в момент, когда указатель мыши находится над ссылкой:blink:

zzz 15.08.2009 18:20

Можно полный код??

Dmitry A. Soshnikov 15.08.2009 19:27

Цитата:

Сообщение от theo_
timerID = setTimeout(hide(menu), 500);

в setTimeout передаётся либо функция (без вызова), либо строка, содержащая код:

- setTimeout(hide, 500);
- setTimeout('hide()', 500);


Первый вариант предпочтительней. Однако, если нужно передать аргумент, то можно использовать так:

setTimeout(function () {
  hide(menu);
}, 500);


Цитата:

Сообщение от theo_
menu.onmouseover = "cancel_hide()";
menu.onmouseout = "hide()";

Аналогично присвоение событиям - должна быть функция, не строка (и не вызов):

menu.onmouseover = cancel_hide;
menu.onmouseout = hide;


Цитата:

Сообщение от theo_
однако оно может убраться и в момент, когда указатель мыши находится над ссылкой

В данном случае, можно ввести переменную-флаг. Если флаг == true, не выполняйте действие; по onmouseout'у можно сбросить флаг и запустить функцию скрытия по тайм-ауту. Хотя, не понятно, зачем запускать функцию скрытия, когда указатель над меню? Запускайте по mouseout'у.

Цитата:

Сообщение от theo_
не получается menu сделать глобальной переменной

объявите вне функций

theo_ 16.08.2009 23:57

Dmitry A. Soshnikov, спасибо огромное за объяснения :thanks:

именно флаг помог сделать все как надо :-)

вот итоговый код решения моей проблемы:
Код:

var timerID = false;
var menu = false;
var menu_on = false;

function show_sub_menu()
{
  menu = document.getElementById("top_submenu");
  menu.style.visibility = "visible";
  menu.onmouseover = cancel_hide;
  menu.onmouseout = hide;
  menu_on = true;
}
function hide_sub_menu()
{
  menu = document.getElementById("top_submenu");
  menu_on = false;
  timerID = setTimeout(hide, 100);
}
function cancel_hide()
{
  menu = document.getElementById("top_submenu");
  menu.style.visibility = "visible";
  clearTimeout(timerID);
}
function hide()
{
  if (menu_on == true) return;
  menu = document.getElementById("top_submenu");
  menu.style.visibility = "hidden";
}


Dmitry A. Soshnikov 17.08.2009 00:30

Цитата:

Сообщение от theo_
menu = document.getElementById("top_submenu");

Если элемент "top_submenu" к моменту работы скрипта уже определён, то, в целях оптимизации (чтобы не вызывать каждый раз .getElementById), можно получить его один раз, при определении переменной menu:

var timerID = false;
var menu = document.getElementById("top_submenu");
var menu_on = false;
...
function show_sub_menu()
{
  menu.style.visibility = "visible";
  ...
}

theo_ 17.08.2009 01:13

Dmitry A. Soshnikov, я пытался так делать , но по какой-то причине у меня все вообще перестает работать.
отлаживать js не умею толком, а alert(menu) или alert(menu.id) вообще ничего не выдает, а точнее даже окна не выводится.
поэтому я и интересовался по поводу глобальной переменной

JSprog 17.08.2009 09:15

а если в алерте в скобках ' ' прописать мне иногда помогает
например alert(m) не работает а alert('m') работает

Dmitry A. Soshnikov 17.08.2009 11:11

Цитата:

Сообщение от theo_
но по какой-то причине у меня все вообще перестает работать

Вероятно, пытаетесь запускать скрипт, когда DOM-элемент (top_submenu) ещё не создан. В данном случае, можно либо запускать скрипт в самом конце (перед </body>), либо использовать событие window.onload (либо же, более современное, onDOMContentLoaded и его эмуляции).

Самый простой вариант:

var menu;

window.onload = function () {
  // здесь код, к этому моменту
  // DOM-элементы должны быть уже доступны
  menu = document.getElementById("top_submenu");
};


Цитата:

Сообщение от JSprog
а если в алерте в скобках ' ' прописать мне иногда помогает
например alert(m) не работает а alert('m') работает

В первом случае - переменная (она может быть не определена), во втором - обычная строка, не имеющая отношения к нечто m.

bassolo 03.10.2009 10:25

У меня вопрос про выподающее меню:
вот js:
<SCRIPT>

function stroy(a)
{
if(a==00) //onMouseout
{
document.menu00.src="10_1.gif"; // 2 
document.menu01.src="0.gif"; // 1 пункт вложенного меню
document.menu02.src="0.gif"; // 2 пункт вложенного меню
document.menu10.src="0.gif"; // левая 1
document.menu20.src="0.gif"; // левая 2
}
if(a==10) // активна главная картинка
{
document.menu00.src="10_2.gif"; // главная картинка (активная)
document.menu01.src="11_1.gif"; // 1 пункт вложенного меню 
document.menu02.src="12_1.gif"; // 2 пункт вложенного меню
document.menu10.src="left_1.gif"; // левая 1
document.menu20.src="left_1.gif"; // левая 2
}
if(a==11) // активен 1 пункт меню
{
document.menu00.src="10_2.gif"; // главная картинка (активная)
document.menu01.src="11_2.gif"; // 1 пункт вложенного меню (активная)
document.menu02.src="12_1.gif"; // 2 пункт вложенного меню
document.menu10.src="left_2.gif"; // левая 1(активная)
document.menu20.src="left_1.gif"; // левая 2
}
if(a==12)// активен 2 пункт меню
{
document.menu00.src="10_2.gif"; // главная картинка (активна)
document.menu01.src="11_1.gif"; // 1 пункт вложенного меню
document.menu02.src="12_2.gif"; // 2 пункт вложенного меню (активен)
document.menu10.src="left_1.gif"; // левая 1
document.menu20.src="left_2.gif"; // левая 2 (активна)
}
}

</SCRIPT>


html:
<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" ALIGN="center" onMouseout="stroy(00);return true;">
	   <TR>
	   	   <TD colspan="2"><A HREF="javascript:void(0);"  onMouseover="stroy(10);return true;" onClick="window.open ('1.html')"; >
	   	   <IMG NAME=menu00 SRC=10_1.gif BORDER=0></a></td>
	   </tr>
	   <tr>
	   	   <TD align="right">
		   <A HREF="javascript:void(0);"  onMouseover="stroy(11);return true;" onClick="window.open ('1.html')";>
		   <IMG NAME=menu10 SRC=0.gif BORDER=0></td></a>
		   <td width="90%"><A HREF="javascript:void(0);"  onMouseover="stroy(11);return true;" onClick="window.open ('1.html')";>
		   <IMG NAME=menu01 title="" SRC=0.gif BORDER=0></TD></a>
		</tr>
		<tr>
			<TD align="right"><A HREF="javascript:void(0);"  onMouseover="stroy(12);return true;" onClick="window.open ('1.html')";>
			<IMG NAME=menu20 SRC=0.gif BORDER=0></td></a>
			<td width="90%"><A HREF="javascript:void(0);"  onMouseover="stroy(12);return true;" onClick="window.open ('1.html')";>
			<IMG NAME=menu02 title="" SRC=0.gif BORDER=0></TD></a>
		</tr>
		
</TABLE>


вот... при наводе мышкой на картинку (stroy(10)) появляется два пункта меню. И когда наводишь на первый пункт, они оба исчезают. При повторном наведении работает. Потом с первого пункта наводим на второй пункт - такая же фигня, оба пропадают. При повторном (т.е. уже третьем!) наведении работает. Все, дальше работает, как надо.
Если, когда все заработало, обновить страницу, то все равно работает. Такая фигня только при открытии страници. Че такое? Подскажите,плиз:)

PS Еще вот это нормально?
<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" ALIGN="center" onMouseout="stroy(00);return true;">

B~Vladi 05.10.2009 10:32

Цитата:

Сообщение от bassolo
<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" ALIGN="center" onMouseout="stroy(00);return true;">

Может быть невалидно, если Doctype XHTML.
Цитата:

Сообщение от bassolo
stroy(00)

Зачем 2 нуля?!

x-yuri 05.10.2009 11:34

зацените, кстати, такой вариант, имхо оптимальный
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
	<title>title</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <style type="text/css">


        ul, li { margin: 0;
                 padding: 0; }
        li { position: relative;
             list-style-type: none;
             background: #ddd;
             margin: 1px;
             width: 100px; }
        ul { position: absolute;
             left: 100px;
             top: -1px; }
        .hidden { display: none; }
    </style>
    <script type="text/javascript">


        window.onload = function() {

			var lis = document.getElementsByTagName('li');
			for( var i=0; i<lis.length; i++ ) {
				lis[i].onmouseover = function() {
console.log('onmouseover', this.firstChild.nodeValue.replace(/(\r|\n)+/, ''));
					var ul = this.getElementsByTagName('ul');
					if( ul.length )
    					removeClass( ul[0], 'hidden' );
				}
				lis[i].onmouseout = function() {
console.log('onmouseout', this.firstChild.nodeValue.replace(/(\r|\n)+/, ''));
					var ul = this.getElementsByTagName('ul');
					if( ul.length )
    					addClass( ul[0], 'hidden' );
				}
			}
        }


		function $( id ) {
			
			return   typeof id == 'string'   ? document.getElementById(id)   : id;
		}


		function removeClass( n, className ) {

			if (! hasClass(n, className))
				return;
			var re = new RegExp( '(^|\\s+)'+className+'($|\\s+)' );
			n.className = n.className.replace( re, ' ' );
		}


		function addClass( n, className ) {

			if( hasClass(n, className) )
				return;
			n.className = [n.className, className].join(' ');
		}


		function hasClass( n, className ) {

			var re = new RegExp( '(^|\\s)'+className+'($|\\s)' );
			return n.className && n.className.match( re );
		}
    </script>
</head>
<body>

<ul>
    <li>1
        <ul class="hidden">
            <li>1-1
                <ul class="hidden">
					<li>1-1-1
					<li>1-1-2</ul>
            <li>1-2
                <ul class="hidden">
					<li>1-2-1
					<li>1-2-2</ul></ul>
    <li>2
        <ul class="hidden">
            <li>2-1
                <ul class="hidden">
					<li>2-1-1
					<li>2-1-2</ul>
            <li>2-2
                <ul class="hidden">
					<li>2-2-1
					<li>2-2-2</ul></ul></ul>

</body>
</html>


Часовой пояс GMT +3, время: 14:04.