Creando unas tabs funcionales sin JQuery, a lo vanilla

Este post es un ejercicio muy sencillo que os puede ayudar a crear un sistema estándar de tabs sin tener que usar JQuery. Porque, como sabréis, JQuery es una buena librería pero como librería que es tiene un gravísimo problema (como ella y todas) y es que es una caja cerrada.

Una caja cerrada no os permite “ver” lo que pasa dentro (si, podéis ver el código fuente de JQuery) y que, por lo tanto, puede hacer tantas cosas indirectamente que puede suponer una alta carga para los equipos. Ademas, aunque no os lo creáis, debido a que JQuery se ha convertido en un must en muchas webs muchas de sus peculiaridades se han incorporado directamente en Javascript.

Empecemos por lo básico. Que han de cumplir nuestras tabs.

Sencillamente nuestra tabs son un sistema donde tenemos una serie de enlaces que cambian un contenido inferior según pulsemos sobre uno u otro enlace. Ademas, han de cumplir que se puedan poner más de una en la misma página sin que entre ellas interfieran. Vamos, lo básico. Por ello veamos el HTML con un ejemplo de tres tabs.

<div class="identificador123 tab_horizontal_left">
          <ul>
            <li class="active"><a href="#tab1">te recomendamos llevarte</a></li>
            <li><a href="#tab2">la prueba en si</a></li>
            <li><a href="#tab3">¿y despues?</a></li>
          </ul>
          <div class="contenido">
            <div id="tab1" class="active">
              <h2>Que llevar</h2>
              <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas nec viverra ligula, et interdum lectus. Cras semper venenatis urna, in semper sapien interdum eu. Vestibulum eleifend porta magna consequat rutrum. Nam scelerisque dolor nec nibh lobortis, in ultrices mi ornare. Curabitur nec leo in nisi pellentesque semper id in enim.</p>
            </div>
            <div id="tab2">
              <h2>La prueba</h2>
              <p>Praesent et sem iaculis, aliquam arcu quis, malesuada felis. Sed id felis ac metus viverra rhoncus vel ac justo. Nulla sodales dapibus elit, non sollicitudin eros iaculis quis. Suspendisse pretium tellus quis arcu sagittis accumsan. Pellentesque viverra, dui id ultricies suscipit, ipsum nunc faucibus turpis, id vulputate eros ex eu est.</p>
              <p>Proin ligula tellus, fringilla ac tempus quis, ultrices et eros. Curabitur sit amet risus vitae lorem ultrices varius nec sed dui.</p>
            </div>
            <div id="tab3">
              <h2>Y despues</h2>
              <p>Cras vulputate est id enim commodo, eu euismod quam fringilla. Pellentesque sodales neque nec sapien consequat, a aliquam quam pellentesque. Mauris eu aliquet felis. Fusce laoreet iaculis turpis, in tempus elit. Aenean in risus a metus suscipit tempor. Ut eget ex in elit rutrum euismod et id dui. Praesent non sem risus.</p>
              <p> Nam vitae luctus nibh, eu porta odio. Aliquam dictum, nulla fermentum blandit aliquet, mi elit faucibus eros, vitae aliquet est est a lorem. Donec eget tempor purus. Phasellus viverra arcu commodo elit dictum, sit amet viverra erat lobortis. In eu porta lorem, sit amet pretium purus. Mauris vel leo eu arcu lacinia lobortis.</p>
            </div>
          </div>
        </div>

Como vemos hemos creado un elemento contenedor que tendra un identificador (para por si hay más de una) dividido en dos zonas. Un ul donde pondremos los enlaces a las tabs y un div contenedor del contenido dividido en tantos divs como tabs haya. Observamos que en los li hacemos una referencia en el enlace al identificador de la tab del contenido. Algo muy simple y nada que contar nuevo.

De hecho, si os fijáis el control de cual estamos viendo lo realizamos a través de la clase “active” en el DOM, con lo que manejando esta mostramos lo necesario.

Pongámoslo un poquito más bonito gracias a la magia del SASS. Para ello nos podemos crear un @mixin que nos genere directamente todo el CSS necesario dependiendo de un parámetro, el como vamos a colocar los botones:

@mixin create_tab_horizontal($alineacion: left) {
  // Crea el tab horizontal y, por ahora, todo lo que se que hace falta
  // $alineacion: como se alinean los botones, por defecto "left" || [right] [center]
  .tab_horizontal_#{$alineacion} {
    margin-top: 1em;
    ul {
      position: relative;
      margin: 0;
      padding: 0;
      text-align: $alineacion;
      a {
        color: #d0d0d0;
          li.active {
            color: #a0a0a0;
          &:hover {
            text-decoration: none;
          }
        }
      }
      li {
        padding: 0.8em 1.3em;
        margin: 0;
        display: inline-block;
        list-style-type: none;
        border-left: 1px solid #d0d0d0;
        border-top: 1px solid #d0d0d0;
        border-right: 1px solid #d0d0d0;
        text-align: center;
        text-transform: uppercase;
        color: #797979;
        border-radius: 4px 4px 0 0;
        &.active {
          border-left: 1px solid #a0a0a0;
          border-top: 1px solid #a0a0a0;
          border-right: 1px solid #a0a0a0;
          color: #a0a0a0;
          a {
            color: #a0a0a0;
          }
        }
      }
    }
    .contenido {
      border: 1px solid #d0d0d0;
      padding: 0.5em;
      & > div {
        //visibility: hidden
        display: none;
        &.active {
          //visibility: inherit;
          display: block;
        }
      }
    }
  }
}

Y ahora, lo más interesante, lo que le da la vida a esto, el Javascript:

function Create_Events_Tab(id_element) {
  // Funcion para el funcionamiento de los tabs
  // id_element: identificador del elemento tab
  var tabs = document.querySelectorAll('.'+id_element+' ul li');
  for (var i = 0; i < tabs.length; i++) {
    tabs[i].addEventListener('click', function(event) {
      for (var i = 0; i < tabs.length; i++) {
        tabs[i].classList.remove('active');
      }
      var clickedTab = event.currentTarget;
      clickedTab.classList.add('active');
      event.preventDefault();

      var mycontentPanes = document.querySelectorAll('.'+id_element+' .contenido div');
      for (i = 0; i < mycontentPanes.length; i++) {
        mycontentPanes[i].classList.remove('active');
      }
      var anchorReference = event.target;
      var activePanedId = anchorReference.getAttribute('href');
      var activePane = document.querySelector('.'+id_element+' '+activePanedId);
      activePane.classList.add('active');
    });
  }
}


Donde, como veis, hemos creado una única función que añade un handler de evento al enlace que lo que hace es quitar el estilo active de todos y ponerlo donde corresponde.

Es decir, la forma de proceder es muy sencilla, localizar todas las tabs con .querySelectorAll que devuelve un objeto DOM con todo lo que haya bajo este y que el parámetro es igual que en JQuery para buscar en el DOM, recorrerles quitando el css "active" con la propiedad classList (que tiene varios métodos para añadir -add-, ver, eliminar -remove- alguno o todos los estilos) y, repetir lo mismo en la zona de content a sabiendas, como hemos hecho, que sacamos a donde apunta el enlace gracias al evento en si y sus propiedades (el target del evento) y a su referencia (su atributo href).

Y listo, funcionando.

¿Y que ventaja tiene todo esto?. Pues prácticamente que aparte de haberlo hecho nosotros y comprender un poco más de las especificación nueva de Javascript (y que vemos que tampoco es tan grande lo que ocupa), al estar usando implementaciones directas del navegador esto va "como un tiro" comparado con hacerlo via JQuery. De hecho, tarda 0,120 ms en comparación con los 2 ms que puede tardar lo mismo en JQuery.

Vale que son tiempos realmente absurdos, pero en una web todo cuenta. Y estas cosas solo se consiguen programando a pelo o "a lo vanilla".

Como desventajas es que no funciona en todos los navegadores, obviamente, que es justo la ventaja de JQuery (aunque también este eliminando soporte para IE 9 hacia abajo -y con razón-). Con lo que lo comido por lo servido.

Por cierto, se me olvidaba, como es una función hay que llamarla en algún momento para que funcione con el identificador del grupo de tabs 🙂

Create_Events_Tab('identificador123');

tuti

Técnico en Comunicación Interna de la UVa

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.