Cookies en Outbook

Esta web utiliza cookies propias para ofrecer una mejor experiencia. Al navegar, aceptas dichas cookies.
  • Más información acerca de las cookies

Outbook

UI-Dev & more

Javascript-Jquery: Galería con desplazamiento (carrusel)

Actualizado 2011-02-18: Se añade una variante con desplazamiento ilimitado.

El objetivo es crear una galería con desplazamiento mediante Javascript manteniendo la accesibilidad cuando no hay soporte Javascript.

HTML

HTML inicial

El HTML inicial podría ser como el que se muestra a continuación:

<div class="componenteGaleria">
  <ul class="clear mostrar-[x]">
    <li>[...]</li>
    <li>[...]</li>
    [...]
    <li>[...]</li>
  </ul>
</div>

Estructura del HTML inicial

Como se puede observar se trata de una capa (DIV) que contiene una lista (UL). La única particularidad es la clase del UL, con el prefijo mostrar- que precede al número de elementos que se quieren tener visibles dentro del carrusel.

Javascript

Para conseguir el efecto de desplazamiento es necesario:

  1. Añadir una clase al elemento contenedor.
  2. Que los elementos del listado estén en una sola línea: habrá que calcular el ancho del total de elementos de lista y aplicárselo a la lista.
  3. Generar una capa para contener la lista y darle a dicha capa el ancho correspondiente al total de elementos que se desee tener visibles.
  4. La capa contenedora de lista deberá llevar position:relative; y overflow:hidden;, y la lista deberá posicionarse absoluta respecto de la capa position:absolute;
  5. Tras la capa contenedora de lista se insertan los controles anterior y siguiente.

Al clicar los controles el listado variará su posicionamiento izquierdo (propiedad CSS left) en una distancia equivalente al ancho de un elemento más sus márgenes, siempre comprobando que el área visible esté llena de elementos, limitando el desplazamiento según sea necesario cuando se escoge la variante limitada (predeterminada). Si se escoge la variante infinita, el listado se desplaza permanentemente en cualquier dirección.

Así quedaría el HTML tras los cambios:

<div class="componenteGaleria">
  
  <div class="contenedor-lista">
    <ul class="clear mostrar-[x]">
      <li>[...]</li>
      <li>[...]</li>
      [...]
      <li>[...]</li>
    </ul>
  </div>
  <ul class="controles">
    <li class="anterior"><a href="#">[...]</a></li>
    <li class="siguiente"><a href="#">[...]</a></li>
  </ul>
</div>

Estructura del HTML modificado con Javascript

Ver ejemplo funcional.

Javascript completo

Primero la llamada a las funciones:

$(document).ready(function () {
  
  // Los llamamos de uno en uno (pendiente de solucionar...)
  $('#contenido .componenteGaleriaLimitada ul').each(function () {
    $(this).carrusel();
  });
  $('#contenido .componenteGaleriaSinLimite ul').each(function () {
    $(this).carrusel({limitada:false});
  });
  
});

La opción limitada (valores true o false) establece si el carrusel es infinito o se para al llegar al final o volver al inicio.

Y el plugin:

(function($){

$.fn.carrusel = function(options){
  var defaults = {
  htmlControles: '<ul class="controles"><li class="anterior"><a href="#"><img src="ficheros/CR_IMG_ico_anterior.png" alt="Anterior" /></a></li><li class="siguiente"><a href="#"><img src="ficheros/CR_IMG_ico_siguiente.png" alt="Siguiente" /></a></li></ul>' // HTML para los controles
  ,htmlContenedorLista: '<div class="contenedor-lista" />' // HTML contenedor de listado
  ,claseContenedorLista: 'contenedor-lista'
  ,claseControlAnterior: 'anterior'
  ,claseControlSiguiente: 'siguiente'
  ,claseJs: 'componenteGaleria-js'
  ,claseOculto: 'indentado'
  ,selectorContenedorLista: '.contenedor-lista'
  ,selectorContenedorComponente: '.componenteGaleria'
  ,selectorContenedorEnlaceControl: '.controles li'
  ,selectorControlAnterior: '.anterior'
  ,selectorControlSiguiente: '.siguiente'
  ,selectorElementoLista: 'li'
  ,selectorOculto: '.indentado'
  
  ,animacion: true // Activar animación 'true', desactivar animación 'false'
  ,limitada:true
};
var datos = {};

var op = $.extend(defaults, options);

return this.each(function(){
  datos.listado = $(this);
  datos.componente = datos.listado.closest(op.selectorContenedorComponente).addClass(op.claseJs);
  prepararLista();
  
  prepararControles();
});

function prepararLista() {
  datos.listado.wrap(op.htmlContenedorLista);
  datos.contenedorLista = datos.listado.parent();
  calculaAncho();
}

function calculaAncho() {
  datos.elementosLista = datos.listado.find(op.selectorElementoLista);
  var numElementosLista = datos.elementosLista.length;
  var i = 0;
  var ancho = 0;
  var margen = 0;

  while (i<numElementosLista) {
    var elementoLista =  datos.elementosLista.eq(i);
    ancho += elementoLista.outerWidth(true);
    margenInocuo = elementoLista.outerWidth(true)-elementoLista.outerWidth();
    if(i+1==numElementosLista && op.limitada){
      margen = elementoLista.outerWidth(true)-elementoLista.outerWidth();
      elementoLista.css('margin','0');
    }
    i++;
  }

  var elementosVisibles = parseInt(datos.listado.attr('class').split('-')[1]);
  datos.anchoElemento = ancho/numElementosLista;
  datos.anchoVisibleGaleria = (datos.anchoElemento*elementosVisibles)-margenInocuo;
  datos.anchoListado = ancho-margen;
  datos.listado.css('width',datos.anchoListado+'px');
  datos.contenedorLista.css('width',datos.anchoVisibleGaleria+'px');
  
  var anchoComponente = datos.contenedorLista.outerWidth(true);
  datos.componente.css('width',anchoComponente+'px');
}

function prepararControles () {
  datos.componente.append(op.htmlControles);
  datos.enlaceControlAnterior = datos.componente.find(op.selectorContenedorEnlaceControl+op.selectorControlAnterior+' a').eq(0);
  datos.enlaceControlSiguiente = datos.componente.find(op.selectorContenedorEnlaceControl+op.selectorControlSiguiente+' a').eq(0);
  datos.enlacesControl = datos.componente.find(op.selectorContenedorEnlaceControl+' a')
  
  if (op.limitada) {prepararControlesLimitada();} else {prepararControlesIlimitada();}
}
function prepararControlesIlimitada () {
  //datos.enlacesControl.unbind('click');
  datos.enlacesControl.click(function (event) {
    event.preventDefault();
    datos.enlacesControl.unbind('click').click(function (event) {event.preventDefault();});
    var direccion = 1;
    if ($(this).closest(op.selectorContenedorEnlaceControl).hasClass(op.claseControlSiguiente)) {
      direccion = -1;
    }
    moverIlimitada(direccion);
  });
}

function moverIlimitada (direccion) {
  var elementos = datos.listado.find(op.selectorElementoLista);
  var primero = elementos.eq(0);
  var ultimo = elementos.last();
  var contenedor = primero.parent();
  
  // Flecha Izquierda
  if (direccion<0) {
    if (op.animacion) {
      datos.listado.animate({left:datos.anchoElemento*(-1)},function () {
        primero.appendTo(contenedor);
        datos.listado.css('left','0');
        prepararControlesIlimitada();
      });
    } else {primero.appendTo(contenedor);prepararControlesIlimitada();}
  }
  
  // Flecha Derecha
  else {
    if (op.animacion) {
      datos.listado.css('left',(datos.anchoElemento*(-1))+'px');
      ultimo.prependTo(contenedor);
      datos.listado.animate({left:0},function () {
        prepararControlesIlimitada();
      });
    } else {ultimo.prependTo(contenedor);prepararControlesIlimitada();}
  }
}

function prepararControlesLimitada () {
  
  
  if (recuperarPosicionActual()==0) {ocultarControl(datos.enlaceControlAnterior);}
  
  
  datos.enlacesControl.click(function (event) {
    event.preventDefault();
    datos.enlacesControl.unbind('click').click(function (event) {event.preventDefault();});
    var direccion = 1;
    if ($(this).closest(op.selectorContenedorEnlaceControl).hasClass(op.claseControlSiguiente)) {
      direccion = -1;
      if (datos.enlaceControlAnterior.hasClass(op.claseOculto)) {mostrarControl(datos.enlaceControlAnterior)}
    } else {
      if (datos.enlaceControlSiguiente.hasClass(op.claseOculto)) {mostrarControl(datos.enlaceControlSiguiente);}
    }
    moverLimitada(direccion);
  })
}

function moverLimitada (direccion) {
  var posicionActual = recuperarPosicionActual();
  
  var posicionNueva = (direccion*datos.anchoElemento)+posicionActual;
  var posicionMaxima = (datos.anchoListado-datos.anchoVisibleGaleria)*(-1);
  
  
  if (posicionNueva>=0) {
    posicionNueva=0;
    ocultarControl(datos.enlaceControlAnterior);
  }
  if (posicionNueva<=posicionMaxima) {
    ocultarControl(datos.enlaceControlSiguiente);
    posicionNueva=posicionMaxima;
  }
  if (op.animacion) {
    datos.listado.animate({left: posicionNueva},function () {prepararControlesLimitada();});
  } else {
    datos.listado.css('left',posicionNueva+'px');
    prepararControlesLimitada();
  }
  
}

function recuperarPosicionActual () {
  return parseInt(datos.listado.css('left').split('px')[0]);
}

function ocultarControl (enlace) {
  enlace.addClass(op.claseOculto);
}

function mostrarControl (enlace) {
  enlace.removeClass(op.claseOculto);
}

}})(jQuery);

Publicado

Categorías: