59 - Menu desplegable accesible.


Otro recurso común de implementar es un menú de opciones desplegable. Implementaremos un menú utilizando listas de HTML. Permitirá múltiples niveles según el anidamiento de los mismos.

Si por algún motivo el lenguaje javascript se encuentra desactivo en el navegador, nuestra página mostrará todos los menúes y submenúes desplegados (es decir nuestro sitio será accesible indistintamente si tiene o no javascript).

pagina.html

<!DOCTYPE html>
<html>
<head>
<title>Problema</title>
<script src="funciones.js"></script>
<link rel="StyleSheet" href="estilos.css" type="text/css">
</head>
<body>
<div id="menu">
<ul>
  <li><a href="http://www.google.com.ar">Google</a></li>
  <li><a href="#">Periódicos >>></a>
    <ul>
      <li><a href="http://www.lanacion.com.ar">La Nación</A></li>
      <li><a href="http://www.clarin.com.ar">El Clarín</A></li>
      <li><a href="http://www.lavoz.com.ar">La Voz</a></li>
    </ul>
  </li>
  <li><a  href="#">Lenguajes >>></a>
    <ul>
      <li><a href="http://www.php.net">PHP</a></li>
      <li><a href="http://www.rubyonrails.org">Ruby on rails</a></li>
      <li><a href="http://www.python.org">Python</a></li>
    </ul>
  </li>
  <li><a  href="http://www.msn.com">MSN</a></li>
</ul>
</div>

</body>
</html>

El archivo html es muy sencillo, sólo debemos tener en cuenta la sintaxis de las listas HTML y hacer correctamente los anidamientos de listas:

<li><a href="#">Periódicos >>></a>
<ul>
<li><a href="http://www.lanacion.com.ar">La Nación</A></li>
<li><a href="http://www.clarin.com.ar">El Clarín</A></li>
<li><a href="http://www.lavoz.com.ar">La Voz</a></li>
</ul>
</li>

Siempre dispondremos las listas dentro de un div al que le definimos su id. Luego, desde javascript, obtendremos la referencia de dicho id.
Tengamos en cuenta también que no inicializamos la propiedad href de los hipervínculos que abren submenúes.
Ahora veamos lo más importante que es el código javascript que se encarga de ocultar o mostrar los submenús.

funciones.js

window.addEventListener('load',inicializarEventos,false);

function inicializarEventos()
{
  inicializarMenu('menu');
}

function inicializarMenu(m)
{
  var ob=document.getElementById(m);
  var menu=ob.getElementsByTagName('ul');
  for(f=1;f<menu.length;f++)
  {
    menu[f].style.display='none';
  }
  var enlaces=ob.getElementsByTagName('a');
  for(f=0;f<enlaces.length;f++)
  {
    enlaces[f].addEventListener('click',itemSeleccionado,false);
  }
}
function itemSeleccionado(e)
{
  var enlace;
  enlace=e.target;
  var padre=enlace.parentNode;
  var ul=padre.getElementsByTagName('ul');
  if (ul.length>0)
  {
    if (ul[0].style.display=='none')
      ul[0].style.display='block';
    else
      ul[0].style.display='none';
  }
}

function addEvent(elemento,nomevento,funcion,captura)
{
  elemento.addEventListener(nomevento,funcion,captura);
  return true;
}

Todo comienza, como todas nuestras páginas, llamando a la función inicializarEventos cuando se acaba de cargar por completo la página en el navegador, para hacer un poco más general nuestro algoritmo de menú, separamos el mismo llamando a la función inicializarMenu y le pasamos como referencia el id del div que contiene el menú:

window.addEventListener('load',inicializarEventos,false);

function inicializarEventos()
{
  inicializarMenu('menu');
}

La función inicializarMenu primero obtiene la referencia del div que contiene el menú:

  var ob=document.getElementById(m);

Seguidamente obtenemos un vector con las referencias a todas las marcas html ul:

  var menu=ob.getElementsByTagName('ul');

Como sabemos, la componente cero del vector tiene la referencia al menú principal que siempre estará visible, por lo que al for siguiente lo inicializamos en 1 para saltear esta primer componente, luego dentro del for accedemos a la propiedad display y la fijamos con el valor 'none', con esto ocultamos todas las listas (menos la principal):

  for(f=1;f<menu.length;f++)
  {
    menu[f].style.display='none';
  }

Seguidamente obtenemos un vector con todos los enlaces del menú y todos los submenúes:

  var enlaces=ob.getElementsByTagName('a');

Por último, le adjuntamos la función a ejecutarse cuando se produzca el evento click a todos los enlaces:

  for(f=0;f<enlaces.length;f++)
  {
    enlaces[f].addEventListener('click',itemSeleccionado,false);
  }

La función itemSeleccionado se dispara para todos las opciones que contiene el menú:

function itemSeleccionado(e)

Lo primero que hacemos es obtener una referencia en la variable 'enlace' al objeto que emitió el evento:

  var enlace;
  enlace=e.target;

Seguidamente obtenemos una referencia al objeto padre:

  var padre=enlace.parentNode;

Con esta obtenemos un vector con todas las listas contenidas en la misma:

  var ul=padre.getElementsByTagName('ul');

Si no tiene listas contenidas estamos en un nivel de opción del menú sin subopciones, en caso que el vector tenga elementos la propiedad length almacena la cantidad:

  if (ul.length>0)

Ahora, si el if se verifica verdadero, analizamos la primera componente del vector ul y si tiene el valor 'none' en la propiedad display la cambiamos por block (esto la hace visible), en caso contrario, ocultamos la lista disponiendo el valor 'none':

    if (ul[0].style.display=='none')
      ul[0].style.display='block';
    else
      ul[0].style.display='none';

Podemos hacer muchisimas mejoras a este menú, pero el objetivo fundamental es entender cada línea del código dispuesto.
En otro concepto agregaremos hojas de estilo para una presentación más adecuada de nuestro menú (lo más importante es que nuestro menú es funcional hasta este momento)


Retornar