Ya hace rato que salió la nueva versión de mootools (la 1.2beta2), hoy quiero mostrar como escribir una clase con esta nueva versión, es muy similar a la versión anterior, pero algunas cosas cambiaron.
Objetivo
El principal objetivo de este artículo es mostrar algunas buenas prácticas al escribir clases, para que sean reutilizables no solo por el [...]
Ya hace rato que salió la nueva versión de mootools (la 1.2beta2), hoy quiero mostrar como escribir una clase con esta nueva versión, es muy similar a la versión anterior, pero algunas cosas cambiaron.
Objetivo
El principal objetivo de este artículo es mostrar algunas buenas prácticas al escribir clases, para que sean reutilizables no solo por el propio autor, sino también por otros desarrolladores, esto hay que tenerlo en mente siempre que escribimos una clase, la clase que se escribirá hará algo asi (En las feeds no se aprecia el efecto debido a que no se ejecuta el javascript):
Este carrusel de imágenes (slideshow) es idéntico (a nivel visor) al que ya he mostrado anteriormente, solo que esta vez el código estará mucho mas limpio y mejor diseñado, completamente orientado a objetos y podrá ser muy flexible para ser utilizado por algún otro desarrollador.
Para comenzar hay que descargar la librería de mootools (1.2beta2) e importarla a la página:
Definir una Clase con Mootools
La clase que hará el trabajo se llamará Carrusel, y para declararla vasta con hacer lo siguiente.
var Carrusel = new Class({
});
Agregar soporte para eventos y opciones
Generalmente una clase lleva Opciones, Eventos y un constructor, no son obligatorios, pero para reutilizar y distribuirla a otras personas, es mejor pensar a futuro.
var Carrusel = new Class({
Implements:[Events, Options], //Implementamos eventos y opciones
options:{
},
initialize:function(el,options){ // el constructor
}
});
Notar que entre cada propiedad o método se separa mediante una coma simple “,”, esto debido al estandar de JSON para javascript.
Para dar soporte de Eventos a la clase hay que implementar la clase Events, al igual que la clase Options si se quiere que la clase sea capas de manejar opciones de una manera sencilla. Este punto en especifico es algo que cambió en esta versión, anteriormente era diferente la manera de implementar clases, ahora esta mucho mas claro y entendible.
Lo siguiente es definir las propiedades (opciones) que la clase tendrá. Tomando en cuenta que es un carrusel de imágenes, tendremos entonces imágenes, sus dimensiones y control sobre el tiempo del efecto de transición y el tiempo a entre cada una.
var Carrusel = new Class({
Implements:[Events, Options],
options:{
images:[],
width: 420,
height: 294,
durationFx:1000,
durationDelay: 3000 //3 segundos
},
initialize:function(el,options){
this.setOptions(options || {});
}
});
Es importante notar que el constructor esta recibiendo dos parámetros, un elemento y opciones.
Las opciones funcionan de la siguiente manera, inicialmente se declaran con los valores por default, en este caso images es un arreglo vacío, width vale 420 y así con las demás, en caso de que en el constructor no se le pasen opciones, entonces las opciones por default serán usadas, este comportamiento se logra gracias a la función this.setOptions, que es la encargada de sobrescribir las opciones por default.
Dentro del constructor de la clase se pueden poner llamadas a otras funciones de la misma clase y hacer cualquier otra cosa, en este caso, voy a crear dos propiedades de clase y dos métodos, por ahora.
initialize:function(el,options){
this.setOptions(options || {});
this.el = $(el);
this.id = this.el.get('id');
this.build();
this.start();
}
Hasta aquí únicamente he creado la propiedad this.el, que es la que guardará una referencia al elemento que se recibe, la propiedad this.id, es el identificador del elemento, esto lo hago por conveniencia, pues mas adelante se hará uso de este varias veces, el método build es el responsable de crear la estructura del visor de imágenes, ósea el html necesario, el método start es el encargado de iniciar la animación.
A continuación voy a mostrar en pseudos código lo que el método build hará.
build:function(){
//1.- Crear un div contenedor e inyectarlo dentro del elemento principal.
//2.- Crear un div para la imagen1 e inyectarlo al contenedor anterior
//3.- Crear un div para la imagen2 e inyectarlo al contenedor anterior
//4.- Crear las los efectos sobre los divs que contenedores de las imagenes
//5.- Iniciar con opacidad al 0%
}
El div del punto uno es necesario, pues es posible que el donde se aloje el carrusel sea otro div posicionado absoluto o flotante, mediante este primer div contenedor nos aseguramos que el carrusel se pueda desplegar correctamente en cualquier lugar.
Una vez claro lo que se hará, codificarlo con mootools es muy sencillo, para crear los divs se utiliza la clase Element, y para los efectos la clase Fx.Tween, el código del método queda de la siguiente manera.
build:function(){
//1.- Crear un div contenedor e inyectarlo dentro del elemento principal.
var content = new Element('div',{id:this.id+'_content',styles:{position:'relative',width:this.options.width+'px',height:this.options.height+'px'}}).inject(this.el);
//2.- Crear un div para la imagen1 e inyectarlo al contenedor anterior
var img1 = new Element('div',{id:this.id+'_img1',styles:{width:'100%',height:'100%'}}).inject(content);
//3.- Crear un div para la imagen2 e inyectarlo al contenedor anterior
var img2 = new Element('div',{id:this.id+'_img2',styles:{position:'absolute',width:this.options.width+'px',height:this.options.height+'px',top:0,left:0}}).inject(content);
//4.- Crear las los efectos sobre los divs que contenedores de las imagenes
this.imgFx1 = new Fx.Tween(img1, 'opacity',{
duration:this.options.durationFx,
onComplete:function(){
this.nextImage();
}.bind(this)
});
this.imgFx2 = new Fx.Tween(img2, 'opacity',{duration:this.options.durationFx});
//5.- Iniciar con opacidad al 0%
this.imgFx1.set(0);
this.imgFx2.set(0);
}
Lo mas interesante para comentar, es que en el punto numero cuatro, no solo se creó el efecto sobre la imagen uno, si no que también se agregó un evento, onComplete, este evento se dispara cuando el efecto sobre la imagen uno ha terminado, entonces la única instrucción aquí es cambiar a la siguiente imagen, el cual es otro método de la clase que mas adelante explicaré. Si eres observador al evento onComplete se le agregó también un bind(this) ,esto es de suma importancia, pues con esta instrucción es posible hacer referencia a la misma clase desde el evento, de no agregar esta instrucción el evento no sabría en que contexto buscar el método nextImage().
El siguiente método a implementar es el start, el cual es el encargado de iniciar con la animación. El pseudo código es el siguiente.
start:function(){
//1.- Revisar si hay imagenes para poder comenzar el carrusel
//2.- Disparar el evento onStart
//3.- Solicitar imagen
//4.- Hacer la trancision inicial
//5.- Crear un temporizador para ejecutar la transición periodicamente
}
El código de lo anterior es el siguiente.
start:function(){
//1.- Revisar si hay imagenes para poder comenzar el carrusel
if(this.options.images.length==0)
return;
//2.- Disparar el evento onStart
this.fireEvent('onStart');
this.index = -1;
this.isImg1OnTop = false;
//3.- Solicitar imagen
this.nextImage();
//4.- Hacer la trancision inicial
this.transition();
//5.- Crear un temporizador para ejecutar la transición periodicamente
this.timer = this.transition.periodical(this.options.durationDelay,this);
}
Es importante mencionan lo que sucede en la instrucción numero dos, para disparar el evento es necesario implementar la clase Events, la cual importamos al principio, this.fireEvent permite disparar eventos, en este caso se dispara el evento cuando se inicia la animación, estos eventos son provistos por los programadores que utilicen esta clase en algún futuro o por nosotros mismo, esto es muy útil si queremos reutilizar esta clase, añadiéndole comportamientos extras cuando sucedan los eventos, es por eso que siempre que se escribe una clase se debiera pensar en agregar eventos, personalmente siempre lo hago y me ha resultado de gran ayuda en el futuro.
En el método start esta haciendo una llamada al método nextImage, este método es el responsable de establecer la imagen al contendor correspondiente, verificando que al término de las imágenes inicie nuevamente desde la imagen número uno, esta función también es invocada cuando termina el efecto de la transición sobre la imagen uno, esto se especifico en la función build, en pseudo código esto es:
nextImage: function(){
//1.- Se incrementa el contador
//2.- Se verifica la dimension del arreglo de imagenes, si llego al limite iniciar desde el principio
//3.- Se verifica si la imagen uno esta actualmente viendose, de esta forma se sabe a donde posicionar la siguietne imagen
}
El código de lo anterior es el siguiente:
nextImage: function(){
//1.- Se incrementa el contador
this.index++;
//2.- Se verifica la dimension del arreglo de imagenes, si llego al limite iniciar desde el principio
if(this.index>=this.options.images.length)
this.index = 0;
//3.- Se verifica si la imagen uno esta actualmente viendose, de esta forma se sabe a donde posicionar la siguietne imagen
if(this.isImg1OnTop)
$(this.id+'_img2').setStyle('background-image','url('+this.options.images[this.index]+')');
else
$(this.id+'_img1').setStyle('background-image','url('+this.options.images[this.index]+')');
}
El método start también esta llamando a la función transition, la responsabilidad del método transition es realizar el efecto sobre los contenedores de la imágenes, esto es muy sencillo:
transition:function(){
this.fireEvent('onTransition');
this.imgFx1.start(this.isImg1OnTop?0:1);
this.imgFx2.start(this.isImg1OnTop?1:0);
this.isImg1OnTop = !this.isImg1OnTop;
}
Lo único que se esta haciendo aquí es disparar el evento onTransition, e iniciando el desvanecido de 0 a 100 por ciento, dependiendo de imagen uno.
Por último se crearán algunos métodos para ser utilizados por otros desarrolladores o por nosotros mismos en otras circunstancias, primeramente un método que detenga al carrusel, otros método para controlar las imágenes, estas pueden provenir de una llamada AJAX o de cualquier otro lugar.
stop:function(){
this.fireEvent('onStop');
$clear(this.timer);
}
newImages:function(images){
this.options.images = images;
},
addImages:function(images){
this.options.images.merge(images);
},
addImage:function(image){
this.addImages([image]);
},
deleteImages:function(){
this.stop();
this.options.images.empty();
}
Utilizar el carrusel o slideshow
Para utilizar el carrusel hay que crear instancias de esta clase, la forma más básica de su uso es:
//Utilizando las propiedades por default.
var car1 = new Carrusel('carrusel1',{images:['images/12.jpg','images/09.jpg','images/05.jpg']});
//Usando los métodos para agregar imagenes
var car3 = new Carrusel('carrusel3');
car3.addImages(['images/14.jpg','images/11.jpg','images/06.jpg']);
car3.addImage('images/10.jpg');
car3.addImage('images/15.jpg');
car3.start();
//Modificando todas las propiedades
var car4 = new Carrusel('carrusel4',{
durationDelay:7000,
durationFx:1500,
width: 500,
height: 280,
images:['images/08.jpg','images/06.jpg','images/13.jpg'],
onStart:function(){console.debug('comenzando...')},
onTransition:function(){console.debug('haciendo la transición')}
});
Hay que recordar que deben existir los elementos en el documento para que funcione correctamente, con esto me refiero a que el HTML debe contener algo como esto para cada instancia del carrusel:
El código completo de la clase carrusel.js es el siguiente:
var Carrusel = new Class({
Implements:[Events, Options],
options:{
images:[],
width: 420,
height: 294,
durationFx:1000,
durationDelay: 3000 //3 segundos
},
initialize:function(el,options){
this.setOptions(options || {});
this.el = $(el);
this.id = this.el.get('id');
this.build();
this.start();
},
build:function(){
//1.- Crear un div contenedor e inyectarlo dentro del elemento principal.
var content = new Element('div',{id:this.id+'_content',styles:{position:'relative',width:this.options.width+'px',height:this.options.height+'px'}}).inject(this.el);
//2.- Crear un div para la imagen1 e inyectarlo al contenedor anterior
var img1 = new Element('div',{id:this.id+'_img1',styles:{width:'100%',height:'100%'}}).inject(content);
//3.- Crear un div para la imagen2 e inyectarlo al contenedor anterior
var img2 = new Element('div',{id:this.id+'_img2',styles:{position:'absolute',width:this.options.width+'px',height:this.options.height+'px',top:0,left:0}}).inject(content);
//4.- Crear las los efectos sobre los divs que contenedores de las imagenes
this.imgFx1 = new Fx.Tween(img1, 'opacity',{
duration:this.options.durationFx,
onComplete:function(){
this.nextImage();
}.bind(this)
});
this.imgFx2 = new Fx.Tween(img2, 'opacity',{duration:this.options.durationFx});
//5.- Iniciar con opacidad al 0%
this.imgFx1.set(0);
this.imgFx2.set(0);
},
start:function(){
//1.- Revisar si hay imagenes para poder comenzar el carrusel
if(this.options.images.length==0)
return;
//2.- Disparar el evento onStart
this.fireEvent('onStart');
this.index = -1;
this.isImg1OnTop = false;
//3.- Solicitar imagen
this.nextImage();
//4.- Hacer la trancision inicial
this.transition();
//5.- Crear un temporizador para ejecutar la transición periodicamente
this.timer = this.transition.periodical(this.options.durationDelay,this);
},
stop:function(){
this.fireEvent('onStop');
$clear(this.timer);
},
transition:function(){
this.fireEvent('onTransition');
this.imgFx1.start(this.isImg1OnTop?0:1);
this.imgFx2.start(this.isImg1OnTop?1:0);
this.isImg1OnTop = !this.isImg1OnTop;
},
nextImage: function(){
//1.- Se incrementa el contador
this.index++;
//2.- Se verifica la dimension del arreglo de imagenes, si llego al limite iniciar desde el principio
if(this.index>=this.options.images.length)
this.index = 0;
//3.- Se verifica si la imagen uno esta actualmente viendose, de esta forma se sabe a donde posicionar la siguietne imagen
if(this.isImg1OnTop)
$(this.id+'_img2').setStyle('background-image','url('+this.options.images[this.index]+')');
else
$(this.id+'_img1').setStyle('background-image','url('+this.options.images[this.index]+')');
},
newImages:function(images){
this.options.images = images;
},
addImages:function(images){
this.options.images.merge(images);
},
addImage:function(image){
this.addImages([image]);
},
deleteImages:function(){
this.stop();
this.options.images.empty();
}
});
El código del documento HTML que lo invoca es:
"http://www.w3.org/TR/xhtml1/DTD/xhtml-strict.dtd">
window.addEvent('domready', function() {
var car = new Carrusel('carrusel');
car.addImages(['images/14.jpg','images/11.jpg','images/06.jpg']);
car.addImage('images/10.jpg');
car.addImage('images/15.jpg');
car.start();
});
Conclusión
Si lo has notado, para escribir esta clase se han creado varios métodos, cada uno con una responsabilidad especifica, la clase esta muy entendible y fácil de utilizar, esto es lo que se debe tener en cuanta cuando se escriben clases.
Espero que este tutorial sea de utilidad para mas de uno, saludos.
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.











18 Responses
Hola, primero que nada felicitarte por el tutorial, es muy bueno, lo hize y todo me funciono a la perfeccion, pero me surgio un problema, tengo una web en la que he creado un accordion con mootools 1.1 y quiero hacer un carrusel en la pmisma pagina y crea incompatibilidad con las diferentes versiones de mootools, como le puedo hacer para que no me cree esa incompatibilidad?
Lo mas rápido y fácil de hacer es descargar la versión 1.2 compatible con la version 1.1, eso es lo que yo hice con este blog para que los ejemplos y tutoriales anteriores siguieran funcionando.
Ve a la página de descargas http://mootools.net/download/tags/1-2b2 selecciona las clases que quieres descargar, y al final hay una opción que permite compatibilidad entre ambas versiones.
Saludos
para extenderlo a un modelo más amigable añadiría este método:
//************************
[code lang="javascript"]
getImages:function(){
var salida = [];
$$('#'+this.id+' img').each(function(element){
salida.push(element.get('src'));
element.remove();
});
return salida;
}
[/code]
/******************
y esta propiedad:
//*************
[code lang="javascript"]
autoImg = false;
[/code]
/**************
en el “initialize” meter después de la linea “this.build();”:
/*********************
[code lang="javascript"]
if(this.options.autoImg)
this.options.images = this.getImages();
[/code]
Gracias por la aportación, solo explicar que con eso se le agrega la capacidad de crear el carrusel con imagenes que ya esten en el documento.
saludos
En primer lugar muchas gracias por este incríble tutorial. Seguro que pornto lo pongo en práctica. Tengo una pregunta: es posible añadir botones de stop, play… y que sea el própio visitante el que active el slideshow? muchas gracias. un saludo
@Sebas
claro, si te das cuenta la clase tiene un método stop, start y nextImage los cuales se pueden llamar por separado mediante botones, únicamente ejecuta el método dentro del evento click de algún boton.
para que no comience la animación sola, es necesario eliminarle o comentarle la linea donde inicia la animación en el constructor.
saludos
hola,
estoy algo atorado con tu tutorial. Estoy utilizando mootools-1.2.1-core-nc.js
dentro de la función
setStyle: function(property, value)
y en la linea 2125
property = property.camelCase();
me dice que property está ‘undefined’
ojalá puedas ayudarme!! gracias!!
lo que pasa es que no descargaste la librería completa, ve a mootools.net y descarga toda la librería no solamente el core.
saludos
Muy interesante y facil de implementar. Tengo solo una duda ¿puedes agregarle algún enlace a cada imagen?
Saludos
Ha Disculpa lo encontre akimismo,
Bueno lo he probado y me va muy bien, Pero tengo una pregunta como hago para que este pare cuando ponga el mouse sobre la foto?
2) como hago para activar controles previuis y Next?
gracias,
Henry
http://www.delchoco.com/damaguarte.php
Son mis fotos de Artesania.
unicamente tendrías que invocar el método “nextImage” en el evento click de algún boton o algo así.
hola queria preguntarte si me podrias ayudar a instalar un carrucel en mi blog, la idea principal es que con facilidad se pueda actualizar diariamente.
te pido de favor una respuesta gracias, te mando saludos desde mexico df.
@Christopher
la verdad no se si blogspot (donde esta alojado tu blog) permita modificar los templates y meterle código, si es posible hacerlo avisame y vemos que podemos hacer.
saludos
Hola, tengo un problema, he bajado la versión 1.2.2 de motools, he seguido los pasos al dedillo, pero me da un error, el firebug me dice que this.el is null en carusell.js linea 13
he probado todo lo que se me ha ocurrido, no se si el error es por la versión mas moderna de motools, agradecería una ayudita.
Saludos.
Hola, ya he solucionado lo del post anterior, era un simple error ortografico, confundi una l con un 1.
Gracias, Saludos.
Hola, he solucionado la tontería del 1 y la l, sigo teniendo problemas con el script, me sigue dando errores y sigo pensando que es por la versión de motools, alguno/a sabe si es compatible con la version 1.2.2 de mootools??
El error segun firebug es :
property is undefined
property = property.camelCase();
http://midominio.com/scripts/mootools-1.2.2-core-nc.js
Line 2171
leí mas arriba que era cosa de las librerías, pero he bajado mootools more completo
Gracias, Saludos. H.
he tratado de hacer mas pequeño el carrusel lo necesito de 4 imagenes unicamente pero me ha sido imposible lograrlo alguien me podrea ayudar a realizarlo
He tratado de usar este codigo y no me ha salido nada solo la primera imagen del img1 es la inica que carga trabajo con xhtml y css