Menú de navegación desplegable II

  • Por
Segunda parte del articulo en el cual vemos como crear un menu desplegable con javascript.
El objetivo que buscamos en este ejercicio es realizar una barra de navegación desplegable, implementada con DHTML y programanda en Javascript. El menú tendrá varios enlaces y se mostrarán otros al pasar el ratón por encima. Existe una primera parte de este artículo, que se debe de leer antes que este. Ver la primera parte del articulo.

Ocultar las capas con un retardo

Para que el menú sea útil de verdad, las capas se deben mostrar y ocular de modo que se permita al usuario acceder a los enlaces de los recuadros y pulsarlos cómodamente. Para ello, tenemos que hacer que las capas de los recuadros se oculten con cierto retardo, para que al salirse de un enlace no se oculte inmediatamente la capa, sino que lo haga pasado un tiempo suficiente para que el usuario pueda operar con el menú.

Por resumir un poco, estas serían las funcionalidades que desearíamos para el menú:

  • Si se pone el ratón sobre un enlace principal se debe mostrar la capa con el recuadro correspondiente. A la vez, si había algún otro recuadro visible, debe ocultarlo. También se debe anular cualquier acción planificada de ocultar la capa del recuadro asociado. La función que hace esto la hemos llamado muestra_coloca().
  • Si se retira el ratón de un enlace principal se debe ocultar la capa con el recuadro correspondiente. Pero esta acción se debe ejecutar con un retardo. Esta acción la llamamos con la función oculta_retarda().
  • Si se coloca el ratón sobre un recuadro se debe evitar que ese recuadro se oculte. Para ello anularemos cualquier acción, que pudiera estar planificada con retardo, que pretenda ocultar la capa sobre la que estamos situados. Esta acción se ejecuta con la función muestra_retarda().
  • Si salimos de una capa con un recuadro planificaremos, con un retardo, la acción de ocultar esa capa. Corresponde también con la función oculta_retarda().
Veremos ahora las capas con las llamadas a los eventos que ejecutan estas funciones:

<table align="center" cellspacing="10">
<tr>
<td><div id=ancla1 class=ancla><a href="#" onmouseover="muestra_coloca('e1')" onmouseout="oculta_retarda('e1')">Enlace 1</a></div></td>
<td><div id=ancla2 class=ancla><a href="#" onmouseover="muestra_coloca('e2')" onmouseout="oculta_retarda('e2')">Enlace 2</a></div></td>
<td><div id=ancla3 class=ancla><a href="#" onmouseover="muestra_coloca('e3')" onmouseout="oculta_retarda('e3')">Enlace 3</a></div></td>
<td><div id=ancla4 class=ancla><a href="#" onmouseover="muestra_coloca('e4')" onmouseout="oculta_retarda('e4')">Enlace 4</a></div></td>
</tr>
</table>

<div id="e1" class=recuadros onmouseover="muestra_retarda('e1')" onmouseout="oculta_retarda('e1')">
<a href="#" class=enlacesbarra>enlace 1.1</a>
<br>
<a href="#" class=enlacesbarra>enlace 1.2</a>
<br>
<a href="#" class=enlacesbarra>enlace 1.3</a>
</div>
<div id="e2" class=recuadros onmouseover="muestra_retarda('e2')" onmouseout="oculta_retarda('e2')">
<a href="#" class=enlacesbarra>enlace 2.1</a>
<br>
<a href="#" class=enlacesbarra>enlace 2.2</a>
</div>
<div id="e3" class=recuadros onmouseover="muestra_retarda('e3')" onmouseout="oculta_retarda('e3')">
<a href="#" class=enlacesbarra>enlace 3.1</a>
<br>
<a href="#" class=enlacesbarra>enlace 3.2</a>
<br>
<a href="#" class=enlacesbarra>enlace 3.3</a>
<br>
<a href="#" class=enlacesbarra>enlace 3.4</a>
<br>
<a href="#" class=enlacesbarra>enlace 3.5</a>
<br>
<a href="#" class=enlacesbarra>enlace 3.6</a>
</div>
<div id="e4" class=recuadros onmouseover="muestra_retarda('e4')" onmouseout="oculta_retarda('e4')">
<a href="#" class=enlacesbarra>enlace 4.1</a>
<br>
<a href="#" class=enlacesbarra>enlace 4.2</a>
<br>
<a href="#" class=enlacesbarra>enlace 4.3</a>
<br>
<a href="#" class=enlacesbarra>enlace 4.4</a>
</div>


El script Javascript para realizar todas esas acciones es el siguiente. Todavía hay bastantes detalles que ver para entenderlo todo.

<script type='text/javascript'>
var empezar = false
var anclas = new Array ("ancla1","ancla2","ancla3","ancla4")
var capas = new Array("e1","e2","e3","e4")
var retardo
var ocultar

function muestra(capa){
xShow(capa);
}
function oculta(capa){
xHide(capa);
}
function posiciona (){
for (i=0;i<capas.length;i++){
posx= xOffsetLeft(anclas[i])
posy= xOffsetTop (anclas[i])
xMoveTo(capas[i],posx,posy+20)
}
}

window.onload = function() {
posiciona()
empezar = true
}
window.onresize = function() {
posiciona()
}

function muestra_coloca(capa){
if (empezar){
for (i=0;i<capas.length;i++){
if (capas[i] != capa) xHide(capas[i])
}
clearTimeout(retardo)
xShow(capa)
}
}

function oculta_retarda(capa){
if (empezar){
ocultar =capa
clearTimeout(retardo)
retardo = setTimeout("xHide('" + ocultar + "')",1000)
}
}

function muestra_retarda(ind){
if (empezar){
clearTimeout(retardo)
}
}
</script>


La variable "empezar" indica si se debe comenzar el movimiento de capas. Puede ser que la página no haya terminado de cargar y que todavía no se hayan posicionado las capas correctamente. Utilizaremos esta variable boleana dentro de las funciones, que no harán nada si no es verdadera.

El array "anclas" contiene una referencia a cada una de las capas ancla. Las introducimos dentro de un array para poder hacer un acceso secuencial a cada capa.

El array "capas" contiene una referencia a cada una de las capas recuadro.

La variable "retardo" guarda una referencia a la acción planificada de ocultar una capa. La utilizaremos para eliminar las acciones planificadas. Es una variable global porque deseamos utilizarla desde varias funciones.

La variable "ocultar" guarda el nombre de la capa que se desea ocultar. Es una variable global porque deseamos que su valor se conserve aunque nos salgamos de la función que la utiliza.

La función posiciona() ahora utiliza el array de capas ancla y recuadros para situar los recuadros en la posición indicada. Como tiene que posicionar todos los recuadros, lo hace con un bucle FOR que recorre todos los elementos del array de capas.

La función muestra_coloca() recibe la capa que se tiene que mostrar. Primero hace un recorrido para ocultar todas las capas y luego muestra la que recibe por parámetro. También anula cualquier acción planificada de ocultar una capa, con la función clearTimeout() a la que se le pasa la variable "retardo".

Por su parte, oculta_retarda() recibe la capa que debe ocultarse, pero con un retardo. Primero introduce en la variable global "ocultar" el nombre de la capa. Anula cualquier acción de ocultar una capa y luego crea, por medio de la función setTimeout() otra planificación para ocultarla al cabo de un segundo. Si la variable "oculta" no fuese global, al salir de esta función se perdería el nombre de la capa que había que ocultar.

Por último muestra_retarda() simplemente elimina cualquier acción planificada de ocultar una capa, con la función clearTimeout() a la que se le pasa la variable "retardo".

Podemos ver el ejemplo desarrollado en una página aparte.

Conclusión

Con esto hemos terminado un menú DHTML avanzado, que hemos tratado de simplificar al máximo. No olvidarse que para que funcione es necesario primero obtener librerías las X-Library en Cross-Browser.com e incluirlas luego en la página desarrollada.

Hay que decir que este sistema no es demasiado sencillo para una persona que no tenga cierta experiencia en el manejo de capas y Javascript. No hemos visto nada nuevo que no se pueda aprender con alguno de los artículos de DesarrolloWeb.com.

Espero que las explicaciones hayan sido claras y que se haya podido completar y entender el ejercicio sin más problemas.

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir

Comentarios

MrGubu

17/2/2005
He probado este código y tiene unproblema: en algunas versiones de IE el menuj aparece desplazado unos 200 px hacia abajo con respecto a donde debe de estar. A ver si alguien sabe cual es el problema.

ELI

17/6/2005
Me tome la libertad de variar el script, me resulto un poco mas pequeño y prescindiendo de la libreria:

<SCRIPT type=text/javascript>
var retardo;

window.onload=oculta;

function oculta(id) {
var d = document.getElementById(id);
for (var i = 1; i<=13; i++) {
if (document.getElementById('smenu'+i))
{document.getElementById('smenu'+i).style.display='none';
clearTimeout(retardo);
}
}
if (d) {d.style.display='block';
clearTimeout(retardo);

}
}

function oculta_retarda(){
clearTimeout(retardo);
retardo = setTimeout("oculta()",1500);
}
</SCRIPT>
</head>
<body>
<div id="subcontenedor">
<ul id="sublista" >
<dl id="menu">
<dt onmouseover="javascript:oculta('smenu1'); "><a href="#">Menu 1</a></dt>
<dd id="smenu1" onmouseover="javascript:oculta('smenu1');" onmouseout="javascript:oculta_retarda();">
<ul>
<li><a href=•#>SubMenu1</a></li>
<li><a href=#>SubMenu2</a></li>
<li><a href=#>SubMenu3</a></li>
</ul>
</dd>
<dt onmouseover="javascript:oculta('smenu2'); "><a href="#">Menu2</a></dt>
<dd id="smenu2" onmouseover="javascript:oculta('smenu2');" onmouseout="javascript:oculta_retarda();">
<ul>
<li><a href=•#>SubMenu1</a></li>
<li><a href=#>SubMenu2</a></li>
<li><a href=#>SubMenu3</a></li>
<li><a href=#>SubMenu4</a></li>

</ul>
</dd>
<dt onmouseover="javascript:oculta('smenu3'); "><a href="#"> Menu3</a></dt>
<dd id="smenu3" onmouseover="javascript:oculta('smenu3');" onmouseout="javascript:oculta_retarda();">
<ul>
<li><a href=•#>SubMenu1</a></li>
<li><a href=#>SubMenu2</a></li>
<li><a href=#>SubMenu3</a></li>
<li><a href=#>SubMenu4</a></li>
<li><a href=#>SubMenu5</a></li>

</ul>
</dd>
</dl>
</ul>
</div>

kaox

06/8/2009
problema
Muy buen aporte pero existe un problema con IE6, lo probe con Firefox y Safari y funciona a la perfect en esos browsers.
Saludos.

nn

06/9/2009
safari
este ejemplo no funciona en safari. alguien sabe cómo solucionar este problema? saludos y gracias

Javigaar

28/1/2012
Gracias!
Buenísimo el tutorial.
Claro, limpio y fácil de implementar.
Una suerte que publiquéis recursos así.
gracias

gerardo simancas

20/11/2012
pregunta
como sería un menu de navegacion desplegable con base de datos? no para 4 enlaces o algo, como haria los arreglos de javascripts?. gracias...