Creamos un plugin jQuery para implementar una barra de navegación con un menú desplegable en varios submenús.
Si lo deseas, puedes ver el menú desplegable dinámico que vamos a realizar.
En diversos artículos de DesarrolloWeb.com hemos tratado sobre la realización de menús desplegables y en esta ocasión vamos a dedicarnos a realizar el sistema utilizando jQuery, por medio de un plugin que cualquier desarrollador pueda utilizar en su propia página web.
Claro que éste no es un problema trivial, puesto que tenemos que trabajar con varias cosas de aquí y de allá: CSS, Javascript y jQuery para realizar el plugin. Afortunadamente tenemos todas las referencias en DesarrolloWeb.com para aprender todo lo que vamos a necesitar.
Objeto para configurar las opciones del menú
Para realizar este ejercicio de la manera más versátil posible hemos implementado una notación para generar las opciones del menú en una variable Javascript de tipo objeto. Es decir, los menús y submenús se especificarán con Javascript y enviaremos ese objeto al plugin para generar el HTML necesario para crearlos en la página.Así que esta es la variable donde definimos el contenido del navegador desplegable:
//un array por cada uno de los menús desplegables
var opciones_menu = [
{
texto: "Enlace 1",
url: "http://www.desarrolloweb.com",
enlaces: [
{
texto: "Enlace 1.1",
url: "#Enlace1-1"
},
{
texto: "Enlace 1.2",
url: "#Enlace1-2"
},
{
texto: "Enlace 1.3",
url: "#Enlace1-3"
}
]
},
{
texto: "DesarrolloMultimedia.es",
url: "http://www.desarrollomultimedia.es",
enlaces: [
{
texto: "Enlace 2.1",
url: "#Enlace2-1"
},
{
texto: "Enlace 2.2",
url: "#Enlace2-2"
}
]
}
];
Como se puede ver se ha definido un array donde tenemos cada uno de los enlaces principales, que a su vez se declaran con un objeto que tiene varias propiedades.
Para cada enlace principal tenemos los datos:
- texto: con una cadena para el texto del enlace
- url: con una cadena para la URL a la que dirigir el enlace
- enlaces: un array con cada uno de los enlaces del submenú asociado a este enlace principal. Los enlaces del submenú que colocamos en este array son otros objetos. Con los siguientes datos:
- texto: el texto para el enlace del submenú
- url: la URL a la que dirigir este enlace del submenú.
Una vez entendido ese formato para el objeto de los enlaces, podemos ver el código del plugin.
////////////////////////////////////////////////////////////////////////////
//creación del plugin generaMenu.
//envío el menú de opciones como parámetro
////////////////////////////////////////////////////////////////////////////
(function($) {
$.fn.generaMenu = function(menu) {
this.each(function(){
var retardo;
var capaMenu = $(this);
//creo e inserto la lista principal
var listaPrincipal = $('<ul></ul>');
capaMenu.append(listaPrincipal);
//enlaces principales
var arrayEnlaces = [];
var arrayCapasSubmenu = [];
var arrayLiMenuPrincipal = [];
//recorro los elementos del menú
jQuery.each(menu, function() {
//ahora en this tengo cada uno de los elementos.
var elementoPrincipal = $('<li></li>');
listaPrincipal.append(elementoPrincipal);
//creo el enlace e inserto
var enlacePrincipal = $('<a href="' + this.url + '">' + this.texto + '</a>');
elementoPrincipal.append(enlacePrincipal);
var capaSubmenu = $('<div class="submenu"></div>');
//guardo la capa submenu en el elemento enlaceprincipal
enlacePrincipal.data("capaSubmenu",capaSubmenu);
//creo una lista para poner los enlaces
var subLista = $('<ul></ul>');
//añado la lista a capaMenu
capaSubmenu.append(subLista);
//para cada elace asociado
jQuery.each(this.enlaces, function() {
//en this tengo cada uno de los enlaces
//creo el elemento de la lista del submenú actual
var subElemento = $('<li></li>');
//meto el elemento de la lista en la lista
subLista.append(subElemento);
//creo el enlace
var subEnlace = $('<a href="' + this.url + '">' + this.texto + '</a>');
//cargo el enlace en la lista
subElemento.append(subEnlace);
});
//inserto la capa del submenu en el cuerpo de la página
$(document.body).append(capaSubmenu);
/////////////////////////////////////////
//EVENTOS
/////////////////////////////////////////
//defino el evento mouseover para el enlace principal
enlacePrincipal.mouseover(function(e){
var enlace = $(this);
clearTimeout(retardo)
ocultarTodosSubmenus();
//recupero la capa de submenu asociada
submenu = enlace.data("capaSubmenu");
//la muestro
submenu.css("display", "block");
});
//defino el evento para el enlace principal
enlacePrincipal.mouseout(function(e){
var enlace = $(this);
//recupero la capa de submenu asociada
submenu = enlace.data("capaSubmenu");
//la oculto
clearTimeout(retardo);
retardo = setTimeout("submenu.css('display', 'none');",1000)
});
//evento para las capa del submenu
capaSubmenu.mouseover(function(){
clearTimeout(retardo);
})
//evento para ocultar las capa del submenu
capaSubmenu.mouseout(function(){
clearTimeout(retardo);
submenu = $(this);
retardo = setTimeout("submenu.css('display', 'none');",1000)
})
//evento para cuando se redimensione la ventana
if(arrayEnlaces.length==0){
//Este evento sólo lo quiero ejecutar una vez
$(window).resize(function(){
colocarCapasSubmenus();
});
}
/////////////////////////////////////////
//FUNCIONES PRIVADAS DEL PLUGIN
/////////////////////////////////////////
//una función privada para ocultar todos los submenus
function ocultarTodosSubmenus(){
$.each(arrayCapasSubmenu, function(){
this.css("display", "none");
});
}
//función para colocar las capas de submenús al lado de los enlaces
function colocarCapasSubmenus(){
$.each(arrayCapasSubmenu, function(i){
//coloco la capa en el lugar donde me interesa
var posicionEnlace = arrayLiMenuPrincipal[i].offset();
this.css({
left: posicionEnlace.left,
top: posicionEnlace.top + 28
});
});
}
//guardo el enlace y las capas de submenús y los elementos li en arrays
arrayEnlaces.push(enlacePrincipal);
arrayCapasSubmenu.push(capaSubmenu);
arrayLiMenuPrincipal.push(elementoPrincipal);
//coloco inicialmente las capas de submenús
colocarCapasSubmenus();
});
});
return this;
};
})(jQuery);
Como se puede ver, gran parte del código es para hacer unos bucles por los que recorrer todo el array de enlaces que pasamos como parámetro al plugin y construir el HTML necesario para el menú.
Luego se crearon unos eventos para mostrar y ocultar los submenús al situarse encima de los enlaces.
Uno de los temas a destacar en este código es que las capas de los submenús se tienen que colocar al lado de los enlaces principales. Para ello, se utiliza la función colocarCapasSubmenus(), que recorre el array de capas del submenú y coloca una a una todas estas capas en una posición absoluta que se calcula en función de la posición del elemento LI donde está el enlace principal.
Ejecutar el plugin para generar el menú desplegable
Ahora sólo nos queda invocar al plugin para generar el menú desplegable. Para eso necesitamos una capa donde mostrar el menú en el código HTML.<div id="menu"></div>
Además, necesitamos el array con los enlaces del menú, que habíamos definido al principio del artículo en la variable "opciones_menu". Esa variable la tenemos que enviar al iniciar el plugin.
$("#menu").generaMenu(opciones_menu);
Con esto ya tenemos el menú funcionando en la página. Sólo nos faltaría un poco de CSS.
CSS para definir el aspecto del menú desplegable
Por último vamos a decorar el menú según nuestros intereses, para que quede acorde con el diseño de nuestra página.Para definir los estilos de los enlaces del menú principal, lo podemos hacer a partir de la capa donde estamos mostrando el menú, a la que habíamos puesto en le código HTML un identificador id="menu". A través de ese identificador podremos definir no sólo el estilo de la propia capa, sino también el estilo de la lista UL que se generará para el menú y de los elementos LI o los enlaces.
#menu{
background-color: #e5e5e5;
padding: 10px;
text-align: center;
overflow: hidden;
}
#menu ul, .submenu ul{
list-style: none;
margin: 0;
padding: 0;
}
#menu li{
margin: 0;
padding: 0 20px 0 10px;
float: left;
}
También podemos estilizar cada una de las capas de los submenús, a las que en el código del plugin le pusimos la clase CSS "submenu". Ese nombre de clase es fijo en el código de nuestro plugin, por lo que una mejora sería que el plugin recibiera el nombre de esa clase en un array de opciones, para que cada usuario lo pudiera configurar.
Como de momento ese nombre de clase no se puede cambiar, tendríamos que aplicar los estilos de esta manera.
.submenu{
display: none;
position: absolute;
padding: 4px 4px 2px;
background-color: #e5e5e5;
}
.submenu li{
padding: 7px 10px;
margin: 4px 0;
background-color: #ffc;
width: 200px;
}
.submenu li:hover{
background-color: #ff6;
}
Como se puede ver, no sólo se aplican estilos a la capa del submenú, sino también a las listas UL que contendrá, sus elementos LI, enlaces, etc.
Así que no hay mucho más que contar sobre este menú desplegable. Seguramente a los lectores se les ocurrirá varias mejoras, pero de momento está bien tal como nos ha quedado y no deseamos complicar aun más el ejercicio.
Si deseas ver el menú desplegable hasta el momento, puedes hacerlo desde este enlace al ejemplo en funcionamiento.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...