JMiur [E]

Para transformar el slideshow que usamos como modelo en todas las entradas y agregarle un efecto de slider, debemos usar JavaScript pero también HTML y CSS porque nos vamos a encontrar con un problema inicial que es decirle al navegador cuáles son las imágenes que queremos desplazar.

Como siempre, hay muchas formas de hacer esto así que vamos con una muy elemental; vamos a utilizar una lista donde en cada item colocaremos una imagen en una etiqueta IMG y un texto en una etiqueta SPAN; cada imagen será, en este caso, de 300x190:
<style>
  .contenedor { /* el DIV que contendrá todo */
    height: 250px;
    margin: 0 auto;
    width: 300px;
  }
  ul#demoanim { /* la lista con las imágenes y los textos */
    height: 220px;
    margin: 0 auto;
    overflow: hidden; /* forzamos a que se oculte todo excepto una imagen */
    position: relative; /* posicionamos la lista de manera relativa */
    text-align: center;
    width: 300px;
  }
  ul#demoanim li { /* cada item de la lista */
    list-style-type: none;
    position: absolute; /* los posicionamos de manera absoluta */
    left: 0;
    top: 0;
    visibility: hidden;  /* y los ocultamos momentáneamente */
  }
  ul#demoanim li img { /* formazos a que las imágenes sean todas iguales */
    height: 190px;
    width: 300px;
  }
  ul#demoanim li span { /* el texto inferior con cualquier tipo de formato */
    display: block;
  }
  .navdemoani { /*a navegación inferior */
    text-align:center;
  }
  .navdemoani a { /* los enlaces de navegación */ }
</style>

<!-- pongo todo dentro de un DIV -->
<div class="contenedor">
  <! -- la lista con imágenes -->
  <ul id="demoanim">
    <li<img src="URL_imagen_1" /><span> la primera de las imagenes </span></li>
    <li><img src="URL_imagen_2" /><span> la segunda imagen </span></li>
    <li><img src="URL_imagen_3" /><span> la tercera imagen </span></li>
    <li><img src="URL_imagen_4" /><span> la cuarta imagen </span></li>
    <li><img src="URL_imagen_5" /><span> la última imagen </span></li>
  </ul>
  <!-- los enlaces para avanzar y retroceder -->
  <div class="nav">
    <a href="javascript:animdemo(1);">anterior</a> | <a href="javascript:animdemo(-1);">siguiente</a>
  </div>
</div>
Así como está, no veremos nada; todas las imágenes están ocultas y superpuestas ya que están posicionadas de manera absoluta en la esquina superior izquierda del rectángulo que las contiene.

Necesitaríamos posicionarlas una al lado de la otra y guardar eso en alguna parte porque, justamente, esa posición es la que vamos a cambiar de manera dinámica y lo que creará el efecto de desplazamiento. El resultado, aunque no se vea, será una tira larga de imágenes, así que si sé que miden 300 pixeles de ancho, la primera debería tener la propiedad left:0px, la segunda left:300px, la tercera left:600px, etc. Si luego de eso las hago visibles, sólo veré la primera porque para eso usé el overflow:hidden.

Podría cambiar el HTML y poner ese dato en cada etiqueta LI pero no tengo ganas de hacer cuentas así que aprovechamos JavaScript para que lo haga por nosotros y de paso, que guarde los datos para que luego podamos manipularlos.

No sé la cantidad de imágenes que hay, no tienen ID, sólo conozco el ID de la lista pero las etiquetas LI no tienen; sin embargo, puedo leer esos datos usando la función getElementsByTagName() que lo que hace es "buscar" las etiquetas HTML que se le indiquen así que le digo que busque dentro del ID que conozco, todas las etiquetas LI que haya:

var listaani = document.getElementById("demoanim").getElementsByTagName("li");

De ese modo, listaani[0] tendrá todos los datos de la primera etiqueta LI, listaani[1] los datos de la segunda, listaani[2] los de la tercera, etc.

Así que, debajo de lo que habíamos hecho, agrego algo así:
<script>
  anchoanimdemo = 300; // es el ancho de las imagenes
  // voy a guardar cada etiqueta LI en un array
  var listaani = document.getElementById("demoanim").getElementsByTagName("li");
  // listaani.length me dirá la cantidad de elementos (cuántas imágenes hay)
  // hago un bucle y voy agregando las propiedades a cada una de ellas
  for(var i = 0; i < listaani.length; i++){
    // la posicion left es pura aritmética: 0*300=0; 1*300=300; 2*300=600; etc
    listaani[i].style.left = (i * anchoanimdemo) + "px";
    listaani[i].style.visibility= "visible";
  }
</script>
Si ahora miro el resultado, veré la primera imagen pero nada más; nos faltan las funciones que produzcan el efecto:
<script type='text/javascript'>
//<![CDATA[
  // voy a inicializar algunas variables
  var timeranimdemo; // el nombre que le daré al timer
  var timerFLAGanimdemo = 0; // un valor que me indicará si estoy aumentando (1)  o disminuyendo (-1) la posición
  var contadoranimdemo; // es lo que usaré para saber cuando detenerme
  var imagenanimdemo = 0; // el número de orden de las imágenes (de las etiquetas LI que guardamos en listaani[] )
  var velocidadanimdemo = 1; // lo usaré para controlar la velocidad del slider
  var anchoanimdemo = 300; // es el ancho de las imágenes

  // esta función es la que se ejecuta al hacer click en los enlaces de la navegación
  // en la dirección habrá un valor de 1 para indicar que se moverá hacia la derecha y un valor de -1 para moverse hacia la izquierda
  function animdemo(direccion) {
    // si el flag no es cero quiere decir que se está animando así que salimos de la función para no ejecutarla varias veces
    if(timerFLAGanimdemo!=0) {
      return;
    }
    // verifico que haya más imágenes
    if(direccion==-1 && imagenanimdemo==(listaani.length-1)) {
      // click en anterior pero estoy en la primera imagen asi que no hago nada
      return;
    }
    if(direccion==1 && imagenanimdemo==0) {
      // click en siguiente pero estoy en la última imagen asi que no hago nada
      return;
    }
    // todo está OK así que inicializo el efecto
    contadoranimdemo = 0; // pongo a cero el contador
    timerFLAGanimdemo = direccion; // guardo la dirección
    // indico que la función timerejemploanimdemo() se ejecute cada milisegundo
    timeranimdemo = setInterval(timerejemploanimdemo,1);
  }

  // y esta es la función que se ejecutará una vez cada milisegundo
  function timerejemploanimdemo() {
    contadoranimdemo++; // incrementamos el contador
    // calculo cuántos pixeles se deben despazar (si la velocidad es 1 y la imagen mide 300, serán 300)
    // si el contador llegó hasta ese valor, detenemos todo
    if(contadoranimdemo>(anchoanimdemo/velocidadanimdemo)) {
      // cancelamos la función y ya no se seguirá ejecutando
      clearTimeout(timeranimdemo);
      // guardo el número índice de la imagen que está visible
      imagenanimdemo = imagenanimdemo - timerFLAGanimdemo;
      // terminamos la animación
      timerFLAGanimdemo = 0;
      return;
    }
    // con un bucle, modifico la propiedad left, sumando o restando una cantidad de pixeles
    for(var i = 0; i < listaani.length; i++){
      posicionactual = parseInt(listaani[i].style.left) + timerFLAGanimdemo * velocidadanimdemo;
      listaani[i].style.left = String(posicionactual) + "px";
    }
  }
//]]>
</script>

4 comentarios:

Manuel Alberto  

Bravo!!! :)
Tengo una duda. La clase .contenedor no entrará en conflicto con otra clase del mismo nombre que pudiera tener el blog, definida para otro script?

Responder
Unknown  

Grande Jmiur, ya probaré :D

Responder
Adrián J. Messina  

Esto se esta poniendo cada vez mejor. Vamos a probrarlo.
Por casualidad me ocurre a mi solo que por momentos se traba el slide? o es probable que ocurra?

Responder
JMiur  

Manfenix:
Si, eso puede ocurrir. Simplemente, coloca cualquier otro nombre de clase o de ID.

Graciela:
Pruebe :D

Adrián:
Si. eso puede ocurrir. Mejor dicho, ocurrirá ya que se mueve pixel por pixel, y no hay una optimización del código o del bucle ya que sólo se trata de un demo.

Responder

¿Quiere dejar un comentario?

recuerde que los comentarios están siendo moderados y serán publicados a la brevedad ...

Nota: sólo los miembros de este blog pueden publicar comentarios.

Si le gusta ir a lo seguro utilice este botón para abrir los comentarios en una ventana modal en esta misma pagina.

Si añora tiempos idos, use este enlace para agregar un comentario al viejo estilo ...

 
CERRAR