Utilizamos cookies propias y de terceros para mejorar nuestros servicios y mostrarle publicidad relacionada con sus preferencias mediante el análisis de sus hábitos de navegación. Si continúa navegando, consideramos que acepta su uso.
Las cookies de este sitio web se usan para personalizar el contenido y los anuncios, ofrecer funciones de redes sociales y analizar el tráfico. Además, compartimos información sobre el uso que haga del sitio web con nuestros partners de redes sociales, publicidad y análisis web, quienes pueden combinarla con otra información que les haya proporcionado o que hayan recopilado a partir del uso que haya hecho de sus servicios. Puede cambiar la configuración u obtener más información aquí

Aceptar

Google

tunait.com » Tutorial » Menú vertical contráctil.


Cómo hacer un menú vertical contráctil.

El concepto es muy similar al expuesto en el tutorial de mostrar y ocultar información. Si bien se podría usar el mismo sistema y código vamos a hacer nuestro menú contráctil de una forma diferente con el fin de aprender otras formas menos intrusivas de hacerlo.

Partimos de que tenemos un menú formado por una lista no ordenada (ol)de links categorizados bajo distintos apartados:

El código HTML es el siguiente

 
       
   <ul>
      <li>Apartado 1 
         <ul>
            <li>secci&oacute;n 1</li>
            <li>secci&oacute;n 2</li>
            <li>secci&oacute;n 3</li>
         </ul>
      </li>
      <li>Apartado 2 
         <ul>
            <li>seccion 4</li>
            <li>secci&oacute;n 5</li>
         </ul>
      </li>
      <li>Apartado 3 
         <ul>
            <li>secci&oacute;n 6</li>
            <li>secci&oacute;n 7</li>
            <li>secci&oacute;n 8</li>
         </ul>
      </li>
   </ul>
     

Nos vamos a ahorrar el asignar identificadores y andar enviándolos a la función Javascript que nos maneje el asunto a base de manejarnos puramente usando el DOM. Cada vez que se llame a la función Javascript enviaremos como único parámetro el propio elemento que la llama usando la sentencia this que lo que hace es referenciarse o indicarse a sí mismo el objeto que dispara el evento.

Si a nuestra función la llamamos Menu(elementoQueLlama) y debemos pasarle el propio elemento que la llama como argumento lo haremos usando this


   <ul>
      <li onclick="Menu(this)"> Apartado 1 
         <ul> ...
     

Y en nuestra función Javascript haremos lo siguiente: lo que queremos es mostrar u ocultar la lista anidada (ul) dentro del elemento del Apartado 1


   <ul>
      <li onclick="Menu(this)"> Apartado 1 
         <ul> ... // ◄ -- este elemento queremos mostrar u ocultar
     

Aprovechando que todos los elementos donde hacer click y los elementos a ser mostrados u ocultados van a tener un patrón estructural común encontraremos al elemento sobre el cual actuar a partir del elemento que activa la llamada a la función y que se referencia a sí mismo mediante this

Observamos que el ul que queremos abrir/cerrar está anidado dentro del elemento li que llama a la función, es decir, es un nodo dentro del elemento li que llama a la función.

El nodo ul a mostrar u ocultar (el tercero del esquema) es un nodo hijo del nodo li con la llamada a Menu(this) (el segundo del esquema).

El nodo li con la llamada a Menu(this) (el segundo del esquema) es el nodo padre del nodo ul a mostrar u ocultar.

Si a la función Javascript Menu(elementoQueLlama) le hacemos una llamada enviando la referencia del propio elemento que la llama como argumento con Menu(this) tendremos dentro de la función la referencia al elemento que la llamó dentro de la variable elementoQueLlama


       function Menu(elementoQueLlama){
            // elementoQueLlama guarda ahora al elemento que llamó a la función
       }
     

¿Y cuál es el elemento que queremos abrir o cerrar? El elemento ul que es un nodo hijo de elementoQueLlama

Vamos a encontrar, lo primero, los elementos ul contenidos en elementoQueLlama usando el método del DOM getElementsByTagName()

elementosUlEnelementoQueLlama = elementoQueLlama.getElementsByTagName('ul')

Ahora tenemos en la variable elementosUlEnelementoQueLlama la lista de ul's que se encuentren dentro del elemento que llamó al script guardados en un array de 0 o más elementos (según lo que se haya encontrado dentro del elemento al que se le hizo click).

Este elemento ul que buscamos será el primer ul definido en elementoQueLlama así que accedemos a él mediante su posición en el array devuelto

elementoQueQueremos = elementosUlEnelementoQueLlama[0];

Bueno, pues ya tenemos localizado el elemento que queremos abrir o cerrar en elementoQueQueremos. Ahora no tenemos más que asignarle la propiedad CSS display a none o a block. Vamos a usar los operadores condicionales para hacerlo:

elementoQueQueremos.style.display = elementoQueQueremos.style.display == 'none' ? 'block' : 'none' ;

Estupendo, no nos queda más que probarlo. Agregamos como atributo el manejador de eventos a los elementos li que deban encargarse de activar el script con la llamada a la función onclick="Menu(this)"

<li onclick="Menu(this)">Apartado 1 ...

¿Y si queremos anidar otro nivel ?

¿Qué pasa si queremos poner otro nivel de profundidad a nuestro menú? Pues sencillamente, que hará cosas raras.

Nos encontramos con que al intentar abrir o cerrar Sección 1 lo que se activa además es el Apartado 1, es decir, el nodo padre de Sección 1.

¿Por qué sucede esto?
Pues es muy sencillo. El elemento li padre (Apartado 1) abarca a todo su contenido; eso incluye la lista anidada y la lista anidada dentro de ésta. De hecho en cualquier parte del área de Apartado 1 (eso incluye márgenes) se nos disparará la llamada a la función en el momento de hacer click. Así que cuando hacemos click en Sección 1 su elemento padre también está recogiendo el evento.

Lo que haremos entonces es cambiar el manejador de eventos a otro elemento que sólo afecte al texto en donde se deba hacer click.

Vamos a meter el texto clickable dentro de un tag strong. Podemos usar cualquier otro tag; si no queremos agregarle ningún sentido semántico a ese texto podemos usar un span pero en este ejemplo usaremos strong.


       <ul>
          <li><strong onclick="Menu(this)">Apartado 1</strong>        
             <ul>
                <li><strong onclick="Menu(this)">sección 1 </strong> 
                   <ul>
                      <li>seccion 1-b</li>
                   </ul>
                </li>
             ...
     

Macanudo, ahora el evento sólo afecta al texto en donde se hará click y no al resto de elementos hijos o padres.

Pero … ahora el script no funciona :-(

Pasa que estamos usando esta referencia

elementosUlEnelementoQueLlama = elementoQueLlama.getElementsByTagName('ul')

y ahora el elementoQueLlama ya no es el li, si no un tag strong hijo de este li y éste strong no contiene a ningún elemento ul, por lo tanto nos devuelve un array (lista) vacío.

La forma de solucionarlo es referenciar al li que nos interesa (el que teníamos referenciado en un principio). Para ello nada más fácil que indicar que queremos al padre del elementoQueLlama

elLiQueQueremos = elementoQueLlama.parentNode

Resumiendo el único cambio que debemos hacer a nuestra línea es este:

elementosUlEnelementoQueLlama = elementoQueLlama.parentNode.getElementsByTagName('ul')

¡Listo! Ya tenemos de nuevo referenciado nuestro elemento para abrir o cerrar. Eso sí, algo importante es que el script funciona en base a un patrón estructural del menú; eso quiere decir que todos los elementos deben estar estructurados de la misma manera, o sea, llamando a la función desde algún tag que implique sólo al texto en donde hacer click y que ese tag sea hijo directo (no nieto) del li padre del ul con el que queramos interactuar.


function Menu(elementoQueLlama){
   elementosUlEnelementoQueLlama = elementoQueLlama.parentNode.getElementsByTagName('ul');
   elementoQueQueremos = elementosUlEnelementoQueLlama[0];
   elementoQueQueremos.style.display = elementoQueQueremos.style.display == 'none' ? 'block' : 'none' ;
}
     

Ahora bien, eso ha estado bien para describir el ejemplo. Yo le pondría unos nombres más sencillos a esas variables :-P y podríamos reducir a sólo dos líneas así


function Menu(el){
   elemento = el.parentNode.getElementsByTagName('ul')[0]
   elemento.style.display = elemento.style.display == 'none' ? 'block' : 'none'
}
     

 

 

 


Copyright © 2006 www.tunait.com todos los derechos reservados