1 .
En qué consiste
2 .
Cómo personalizar los menús
3 .
Cómo funcionan por dentro
3.1 .
Objeto Menu
3.2 .
Eventos
Uno de los usos más extendidos
del HTML dinámico son estas barras de menús, al estilo
de las que puedes ver en las páginas de
Microsoft o
Silicon Graphics.
En qué consiste
Si pulsáis sobre los enlaces indicados
arriba podréis ver unos menús desplegables muy bien hechos.
Los nuestros no van a ser tan espectaculares, principalmente para que sea
más sencillo entender cómo se hacen.
Podéis comprobar las características de nuestros menús en
este ejemplo.
Si este truco resulta de vuestro interés, procuraremos mejorarlo en
próximas entregas.
Ahora veremos cómo se hace. Es recomendable que sepáis
algo de HTML dinámico
para entenderlo mejor.
Cómo personalizar los menús
Lo primero que vamos a ver son las cosas que deberemos cambiar
para poder reutilizar el código en vuestras páginas.
Lo primero que necesitamos es una clase CSS a la que llamaremos
menu y que definirá el aspecto que
tienen las capas de menú:
.menu {
position:absolute;
visibility:hidden;
background-color: white; // Color de fondo para Explorer
layer-background-color: white; // Color de fondo para Netscape
color: black;
border-style: solid;
border-color: black;
border-width: 1px;
padding: 3px;
font-size : 12px;
font-family: "arial", "helvetica";
}
.menu A:hover {text-decoration: underline; color: blue;}
.menu A {text-decoration: none; color: black;}
Lo que estamos haciendo es señalar al navegador que los elementos
de clase menu serán capas que posicionaremos
de manera absoluta, con un borde negro, un fondo blanco, y cuyos enlaces serán
subrayados de la manera que vimos en el artículo anterior. Todas
las propiedades que definen el aspecto de las capas las podéis
modificar a vuestro gusto.
También debemos definir que habrá dentro de cada
menú. Eso lo haremos por medio de etiquetas DIV dentro del
cuerpo del documento:
<DIV id="menu0" CLASS="menu">
<A HREF="../../recursos/img.htm">Imágenes</A><BR>
...
</DIV>
Serán capas de clase menu que,
en nuestro caso, contendrán sólo una lista de enlaces. En
el vuestro, si lo deseáis, podéis incluir imágenes y
todo lo que se os ocurra.
Ahora tenemos que incluir los enlaces que provocarán el
despliegue del menú en caso de que el ratón pase por encima
de ellos.
<A HREF="pagina.htm" onMouseOver="if (menu[0]) menu[0].activar();">...</A>
Incluimos la condición porque puede suceder que el usuario
intente activar el menú cuando éste todavía no existe,
es decir, cuando todavía no ha acabado de leerse la página
Para asegurarnos de que los visitantes que no tengan la suerte
de poseer un navegador de cuarta generación recorrer nuestras
páginas, el enlace irá a una página desde la cual
podamos acceder a todas las opciones del menú. También
debemos incluir, como controlador del evento
mouseover, una llamada al método
activar del objeto Menu que queramos
desplegar.
Claro, que para saber cómo se llama el objeto Menu
que queremos desplegar en cada enlace, deberemos inicializar dentro del código
todos los objetos de tipo Menu que se
encargarán de desplegar los menús. Esto se hace dentro
de la función inicializar, situada
al final del código JavaScript de la página:
function inicializar() {
...
menu[0] = new Menu("menu0", 20, 5);
menu[1] = new Menu("menu1", 20, 93);
menu[2] = new Menu("menu2", 20, 250);
}
En el ejemplo existen tres menús, que deberán ser los
tres primeros elementos del vector menu. Cada
uno de ellos es inicializado por medio de la línea
menu[i] = new Menu(idMenu, posY, posX);
Donde idMenu es el nombre que,
por medio del parámetro ID, le hemos
puesto a la capa que contiene el menú; siendo
posX y posY
el desplazamiento respecto a la esquina superior izquierda del documento donde
queremos que aparezca el menú. Este valor hay que colocarlo a mano,
por medio del afamado método de ensayo y error.
Si te asaltan las dudas en algún punto, es recomendable
ver el código fuente del ejemplo.
Cómo funcionan por dentro
En general, lo primero que se debe hacer siempre en una aplicación
que utiliza HTML dinámico es ver con qué navegador se está
viendo la página. Para eso utilizaremos un objeto específico:
Objeto DetectorNavegador
function DetectorNavegador() {
this.NS4 = document.layers;
this.IE4 = document.all;
this.DHTML = this.NS4 || this.IE4;
}
var soporta = new DetectorNavegador();
En realidad con un par de variables hubiera bastado, pero así
podéis ver cómo se crea y se aplica un objeto creado por nosotros.
La función DetectorNavegador es un
constructor que llamaremos con el operador new.
El constructor comprueba la existencia de objetos específicos de cada
uno de los navegadores y vincula esa existencia al valor lógico de
las propiedades NS4, IE4
y DHTML.
Ahora necesitaremos un par de variables globales:
var menu = new Array();
var menuActivo = null;
El vector menu contendrá todos
los objetos Menu, mientras que la variable
menuActivo será una referencia
al objeto Menu que contenga al menú que
esté desplegado en estos momentos, siendo null
si no hay ningún menú desplegado.
Objeto Menu
Este objeto es el encargado de manejar los menús. Para su correcto
funcionamiento necesita que hayamos creado las dos variables señaladas
anteriormente y el objeto soporta de tipo
DetectorNavegador. Para entender cómo
funciona vamos a esudiarlo por partes. Lo primero será examinar
el constructor:
function Menu(capaID, top, left) {
this.activar = activarMenu;
this.mostrar = mostrarMenu;
this.ocultar = ocultarMenu;
this.cambiarPosicion = cambiarPosicionMenu;
this.capaRefStr = (soporta.NS4) ?
'document["'+capaID+'"]' :
'document.all["'+capaID+'"]';
this.estiloRefStr = (soporta.NS4) ? '' : '.style';
this.topRefStr = (soporta.NS4) ? '.top' : '.pixelTop';
this.leftRefStr = (soporta.NS4) ? '.left' : '.pixelLeft';
this.cambiarPosicion(top, left);
}
Lo primero que hace el mismo es convertir en métodos de la
función a cuatro funciones que posteriormente estudiaremos. Luego
declara cuatro propiedades que serán cadenas que nos permitirán
acceder a las propiedades de la capa que contiene al menú, dependiendo
del navegador que utilicemos (ya que la jerarquía de objetos en uno
y otro es distinta).
La propiedad capaRefStr contiene
una cadena que contiene la referencia a la capa que contiene el menú.
estiloRefStr contiene la referencia a las
propiedades de una capa y, finalmente, topRefStr
y leftRefStr indican qué propiedad
específica hay que cambiar para modificar la posición de la
capa.
Por último, el constructor llama a la función encargada
de cambiar la posición del menú para colocarla donde haya
indicado el usuario al crear el objeto.
Por último, veamos como funcionan los métodos del
objeto:
function activarMenu() {
if (soporta.DHTML && menuActivo != this) {
if (menuActivo) menuActivo.ocultar();
menuActivo = this;
this.mostrar();
}
}
Este primer método se encarga de desplegar el menú.
Primero comprueba que nuestro navegador lo soporte y que el menú no
esté ya desplegado. Luego, si hay otro menú desplegado,
llama al método ocultar del mismo.
Finalmente, asigna la variable menuActivo
al menú y lo despliega llamando al método
mostrar.
function mostrarMenu() {
eval(this.capaRefStr + this.estiloRefStr + '.visibility = "visible"');
}
function ocultarMenu() {
eval(this.capaRefStr + this.estiloRefStr + '.visibility = "hidden"');
}
Estos dos métodos se encargan de mostrar u ocultar el menú,
respectivamente. Para ello utilizan dos de las cuatro propiedades creadas
en el constructor. Lo que hacen es crear una cadena que contenga una
sentencia que haga el trabajo. Luego llaman a la función predefinida
eval, que se encargará de ejecutar
dicha sentencia.
Dado que éstas funciones sólo se llaman desde
activarMenu, una vez éste ha comprobado
que el navegador soporta DHTML, ya no necesitan código que realice
dicha comprobación.
function cambiarPosicionMenu(top, left) {
if (soporta.DHTML) {
eval(this.capaRefStr + this.estiloRefStr + this.topRefStr + ' = top');
eval(this.capaRefStr + this.estiloRefStr + this.leftRefStr + ' = left');
}
}
Por último, y al igual que las dos funciones anteriores, este
método cambia la posición del menú utilizando las
propiedades creadas en el constructor.
Eventos
Como hemos visto, hemos incluido la llamada al método
activar dentro del controlador de evento
onMouseOver de los enlaces. Pero no hemos
incluido ninguna manera de comprobar que el usuario ha pulsado el ratón
para ocultarlos. Eso lo lograremos interceptando los eventos. Desafortunadamente,
la manera de hacerlo también es distinta en cada navegador, pero
haremos lo que podamos.
Dentro de la función de inicialización que vimos antes
tenemos el código encargado de realizar la intercepción:
function inicializar() {
if (soporta.DHTML) {
if (soporta.NS4)
document.captureEvents(Event.MOUSEUP);
document.onmouseup = ocultarMenuActivo;
}
...
}
No vamos a entrar en los distintos modelos de eventos. Por ahora basta
decir que la última línea indica la función que se
ejecutará si pulsamos el ratón en alguna parte del documento
actual. Las dos anteriores indican al Netscape Communicator que
deseamos interceptar ese tipo de eventos. El Explorer no necesita que se
lo digamos.
La función que se llamará es, por tanto, ésta:
function ocultarMenuActivo(e) {
if (menuActivo) {
menuActivo.ocultar();
menuActivo = null;
}
}
Comprueba si existe algún menú desplegado, para ocultarlo
y poner la variable menuActivo a
null, para indicar que ya no hay menús
desplegados.