jQuery: slideshow di immagini con controlli

jQuery: slideshow di immagini con controlli

In questo articolo vorrei mostrarvi l'implementazione di uno slideshow di immagini in jQuery provvisto di controlli per navigare tra le immagini e di un pulsante per interrompere o riprendere l'animazione delle immagini. Quando un'immagine scompare con un effetto di dissolvenza, il controllo dell'immagine corrente viene enfatizzato da una classe CSS apposita. L'utente può anche cliccare su un singolo controllo per accedere direttamente all'immagine. Implementeremo il tutto con un oggetto singleton e con l'aiuto di alcuni stili CSS.

Partiamo dalla seguente struttura HTML:


<div id="container">
	<div id="rotator_wrapper">
		<ul id="rotator">
			<li id="photo_1">
				<img src="photo_1.jpg" alt="" />
			</li>
			<li id="photo_2">
				<img src="photo_2.jpg" alt="" />
			</li>
			<li id="photo_3">
				<img src="photo_3.jpg" alt="" />
			</li>
			<li id="photo_4">
				<img src="photo_4.jpg" alt="" />
			</li>
			<li id="photo_5">
				<img src="photo_5.jpg" alt="" />
			</li>
		</ul>
		<ul id="rotator_controls">
			<li>
				<a href="#photo_1" class="current">1</a>
			</li>
			<li>
				<a href="#photo_2">2</a>
			</li>
			<li>
				<a href="#photo_3">3</a>
			</li>
			<li>
				<a href="#photo_4">4</a>
			</li>
			<li>
				<a href="#photo_5">5</a>
			</li>
		</ul>
		<a href="#" id="rotator_play_pause">PAUSA</a>
	</div>
</div>

Ci sono tre elementi principali:

  1. #rotator: Contiene le nostre immagini. Ciascuna voce di lista ha un ID univoco.
  2. #rotator_controls: Contiene i controlli per la navigazione dello slideshow. Ciascun link è collegato ad una voce del precedente elemento tramite un'ancora specifica.
  3. #rotator_play_pause: Si tratta del controllo per mettere in pausa o riprendere l'animazione delle immagini.

Con i CSS dobbiamo inizialmente nascondere le immagini e quindi posizionare i controlli sopra lo slideshow:


#rotator li {
	display: none;
}

#container {
	width: 500px;
	height: 375px;
	margin: 2em auto;
}

#rotator_wrapper {
	overflow: hidden;
	position: relative;
	width: 500px;
	height: 375px;
}

#rotator_wrapper li {
	list-style: none;
}

#rotator,
#rotator li,
#rotator img {
	width: 500px;
	height: 375px;
}

#rotator {
	background: #fff;
	position: relative;
}

#rotator li {
	position: absolute;
	top: 0;
	left: 0;
}

#rotator_controls {
	overflow: hidden;
	position: absolute;
	top: 5px;
	left: 2px;
}

#rotator_controls li {
	display: inline;
	float: left;
	margin: 0 0 0 3px;
	width: 30px;
}

#rotator_play_pause,
#rotator_controls a {
	background: #ccc;
	border: 1px solid #000;
	color: #999;
	display: block;
	font: bold 76% Verdana, sans-serif;
	padding: 1px 5px 2px;
	text-align: center;
	text-decoration: none;
}

#rotator_controls a.current {
	color: #000;
	text-decoration: underline;
}

#rotator_play_pause:hover,
#rotator_controls a:hover {
	background: #000;
	border-color: #fff;
	color: #fff;
}

#rotator_play_pause {
	position: absolute;
	top: 5px;
	right: 5px;
}

Come si può notare, abbiamo usato il posizionamento contestuale per posizionare i controlli dello slideshow.

Con jQuery dobbiamo per prima cosa creare il nostro oggetto:


var ImageRotator = new function() {

	// ... codice qui

}();

Quindi dobbiamo definire la velocità dell'animazione:


// ... codice qui

var speed = 2000;

Settiamo poi un flag booleano per sapere se l'animazione è in pausa o meno:


var pause = false;

Creiamo il metodo privato resume(), che svolge due compiti:

  1. fa riprendere un'animazione messa in pausa
  2. invoca in modo ricorsivo il metodo privato rotate() che gestisce l'animazione

Questo metodo accetta come parametro l'elemento corrente contenente l'immagine:


var resume = function(element) {
	
	rotate(element);
	
};

Il metodo principale è rotate(), che accetta come parametro l'elemento corrente da animare. Questo metodo esordisce verificando se l'animazione è stata messa in pausa o meno. Se l'animazione è in pausa, allora il codice di questo metodo non può essere eseguito:


var rotate = function(element) {
	
	if(pause) {
		
		return;
		
	}
	
	// ... continua
};

Ora abbiamo bisogno di stabilire qual'è l'immagine corrente e il link corrente nel menu dei controlli. Otteniamo queste informazioni usando due costrutti ternari:


var $li =  $(element).next('li').length ? $(element).next('li') : $('#rotator li:first');
var $a = $('#rotator_controls a.current').parent('li').next('li').length ? $('#rotator_controls a.current').parent('li').next('li').find('a') : $('#rotator_controls a:first');

Questi due costrutti significano: se esiste un elemento successivo a quello corrente, usa quello, altrimenti usa il primo elemento del set a cui appartiene l'elemento (perchè in quel caso significa che abbiamo raggiunto la fine del set scelto).

A questo punto animiamo l'immagine corrente ed evidenziamo il link corrispondente con la classe CSS current:


$(element).fadeOut(speed, function() {
		
	$('#rotator_controls a.current').removeClass('current');
		
    $li.fadeIn(speed);
		  
    $a.addClass('current');
		  
		  
    resume($li);
		
		
});

Ossia:

  1. l'immagine corrente (element) sparisce
  2. il link che ha già la classe current ne viene privato
  3. l'immagine successiva ($li) appare
  4. il link corrispondente a tale immagine riceve la classe current
  5. il metodo resume() invoca in modo ricorsivo il metodo rotate() sull'immagine successiva, chiudendo il ciclo

Quindi dobbiamo gestire il pulsante per mettere in pausa e far riprendere l'animazione e i link di navigazione. Lo facciamo tramite il metodo privato controls():


var controls = function() {
	
		$('a', '#rotator_controls').click(function(event) {

			$('#rotator_play_pause').text('PLAY');

			$($(this).attr('href')).show().siblings('li').hide();

			$(this).addClass('current').parent('li').siblings('li').find('a').removeClass('current');

			pause = true;
			
			this.blur();
			
			event.preventDefault();

       });
       
       $('#rotator_play_pause').click(function(event) {

			if ($(this).text() === 'PAUSA') {

				pause = true;

				$(this).text('PLAY');

			} else {

				pause = false;

				rotate('li:visible:first', '#rotator');

				$(this).text('PAUSA');
			}

			this.blur();
			event.preventDefault();
		});



	
	
};

Questo metodo è diviso in due routine:

  1. Gestione dei link di navigazione: Quando l'utente fa click su un link, appare la scritta PLAY sul pulsante di animazione. Il link corrente riceve la classe current e viene usata la sua ancora per selezionare e mostrare direttamente l'immagine con ID corrispondente. L'animazione viene messa in pausa settando il flag pause su true.
  2. Gestione del pulsante di animazione: Se il testo dell'elemento è PAUSA, l'animazione viene messa in pausa e il testo viene cambiato in PLAY. Altrimenti, la pausa viene interrotta e viene invocato il metodo rotate() sulla prima immagine visibile e il testo viene impostato su PAUSA.

Nota

L'evento blur viene usato sui link per impedire ai browser di aggiungere contorni dinamici. Lo stesso risultato si può ottenere tramite la dichiarazione CSS outline-style: none sullo stato :focus dei link.

Infine, creiamo il metodo pubblico init() che inizializza il nostro codice:


this.init = function() {
	
	  $('li:first', '#rotator').show();
	  controls();
	  rotate('li:visible:first', '#rotator');
	
	
};

Usiamo il nostro oggetto in questo modo:


$(function() {

	ImageRotator.init();

});

Il codice finale è il seguente:


var ImageRotator = new function() {

	var speed = 2000;
	var pause = false;
	
	var resume = function(element) {
	
		rotate(element);
	
	};
	
	var rotate = function(element) {
	
		if(pause) {
		
			return;
		
		}
		
		var $li =  $(element).next('li').length ? $(element).next('li') : $('#rotator li:first');
		var $a = $('#rotator_controls a.current').parent('li').next('li').length ? $('#rotator_controls a.current').parent('li').next('li').find('a') : $('#rotator_controls a:first');
		
		
		
		



		
		$(element).fadeOut(speed, function() {
		
		  $('#rotator_controls a.current').removeClass('current');
		
		  $li.fadeIn(speed);
		  
		  $a.addClass('current');
		  
		  
		  resume($li);
		
		
		});
		
		

	
	};
	
	var controls = function() {
	
		$('a', '#rotator_controls').click(function(event) {

			$('#rotator_play_pause').text('PLAY');

			$($(this).attr('href')).show().siblings('li').hide();

			$(this).addClass('current').parent('li').siblings('li').find('a').removeClass('current');

			pause = true;
			
			this.blur();
			
			event.preventDefault();

       });
       
       $('#rotator_play_pause').click(function(event) {

			if ($(this).text() === 'PAUSA') {

				pause = true;

				$(this).text('PLAY');

			} else {

				pause = false;

				rotate('li:visible:first', '#rotator');

				$(this).text('PAUSA');
			}

			this.blur();
			event.preventDefault();
		});



	
	
	};
	
	this.init = function() {
	
	  $('li:first', '#rotator').show();
	  controls();
	  rotate('li:visible:first', '#rotator');
	
	
	};

}();

$(function() {

	ImageRotator.init();

});

Potete visionare l'esempio finale in questa pagina.

Torna su