jQuery: creare una galleria lightbox senza usare plugin

jQuery: creare una galleria lightbox senza usare plugin

Usando jQuery ci troviamo spesso di fronte allo stesso dilemma: dobbiamo usare un plugin per un progetto specifico? Dipende spesso dai requisiti del progetto. In altre parole: quanto codice e quanto tempo sono necessari per ottenere un determinato risultato? Si tratta di una questione di tempo. Dal momento che spesso non abbiamo il tempo necessario a causa della scadenza dei tempi di consegna, a volte è necessario usare un plugin. Altre volte invece, specie quando il progetto ha delle specifiche che non si trovano facilmente implementate in un plugin, possiamo sviluppare una nostra implementazione. Vediamo il secondo caso.

Requisiti del progetto

Un cliente vuole che le immagini ridimensionate inserite nelle pagine siano trasformate in una galleria con effetto lightbox. La galleria dovrà essere qualcosa di molto semplice: una finestra modale con un sistema di navigazione e paginazione delle immagini e un elemento di overlay sottostante semitrasparente.

Quando si clicca su un'immagine, la galleria deve comparire mostrando l'immagine corrente come prima immagine e le altre immagini nascoste. Usando la navigazione si mostrano le altre immagini con un effetto di assolvenza.

La marcatura

Il codice HTML è il seguente:


<a href="percorso/immagine-full.jpg" class="gallery">
	<img src="percorso/immagine-resized.jpg" alt="Testo" />
</a>

Con jQuery dobbiamo creare la seguente struttura da inserire alla fine dell'elemento body:


<div id="overlay"></div>
<div id="gallery">
	<div id="gallery-wrapper">
		<img id="first-image" />
	</div>
	<div id="gallery-nav"></div>
</div>

Il codice CSS

Useremo il posizionamento assoluto per visualizzare la galleria e l'elemento di overlay. Quest'ultimo elemento avrà un'altezza assegnata dinamicamente da jQuery:


#overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    background: rgba(0, 0, 0, 0.7);
    display: none;
}

#gallery {
    width: 500px;
    height: 400px;
    border: 5px solid #eee;
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -210px 0 0 -260px;
    background: #fff;
    display: none;
}

#gallery-wrapper {
    width: 400px;
    height: 300px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -150px 0 0 -200px;
}

#gallery-nav {
    height: 2em;
    width: 100%;
    position: absolute;
    bottom: 0;
    left: 0;
    background: #f6f6f6;
    border-top: 1px solid #eee;
    text-align: center;
}

#gallery-nav a {
    display: inline-block;
    height: 1.6em;
    width: 1.6em;
    line-height: 1.6;
    margin: 0.2em 0.5em 0.2em 0;
    text-align: center;
    text-decoration: none;
    color: #333;
    background: #ddd;
}

#gallery-wrapper img {
    max-width: 100%;
    display: none;
}

#gallery-wrapper > img:first-child {
    display: block;
}

Il codice jQuery

Useremo un oggetto Gallery con vari metodi. Essi dovranno:

  1. ottenere il percorso e l'attributo alt dell'immagine corrente
  2. inserire le altre immagini nella gallery quando l'utente attiva la lightbox
  3. generare la struttura HTML della gallery (vista sopra)
  4. aggiungere i link alla navigazione in modo tale che ciascun link abbia un attributo data- che punti all'indice dell'immagine corrispondente
  5. popolare e mostrare la galleria
  6. gestire la navigazione
  7. nascondere la galleria e resettarne la struttura DOM.

Ecco il nostro oggetto:


var Gallery = {
    utils: {
        getCurrentImage: function(element) {
            var $img = $('img', element),
                src = $img.attr('src'),
                alt = $img.attr('alt');
            return {
                src: src,
                alt: alt
            }

        },

        insertOtherImages: function(element) {
            var parent = element.parents('#content');
            var links = parent.find('a.gallery').not(element);
            links.each(function() {
                var $link = $(this);
                var image = Gallery.utils.getCurrentImage($link);
                $('<img/>').attr({
                    src: image.src,
                    alt: image.alt
                }).appendTo('#gallery-wrapper');


            });


        }


    },

    fn: {
        createGallery: function() {
            $('<div id="overlay"/>').
            css('height', $(document).height()).
            appendTo('body');
            $('<div id="gallery"/>').insertAfter('#overlay');
            $('#gallery').html('<div id="gallery-wrapper"></div><div id="gallery-nav"></div>');
            $('<img id="first-image"/>').appendTo('#gallery-wrapper');
        },
        populateGallery: function() {
            $('a.gallery').each(function(i) {
                $('<a/>').attr({
                    href: '#',
                    'data-image': i
                }).text(i + 1).appendTo('#gallery-nav');

            });

        },
        showGallery: function() {
            $('a.gallery').on('click', function(e) {
                e.preventDefault();
                var $a = $(this);
                var image = Gallery.utils.getCurrentImage($a);

                $('#first-image').attr({
                    src: image.src,
                    alt: image.alt
                });

                Gallery.utils.insertOtherImages($a);

                $('#overlay').fadeIn(400, function() {
                    $('#gallery').fadeIn(400);

                });

            });

        },

        navigate: function() {
            $('a', '#gallery-nav').live('click', function(e) {
                e.preventDefault();
                var index = $(this).data('image');
                $('img', '#gallery-wrapper').eq(index).fadeIn(600).siblings('img').hide();

            });

        },

        closeGallery: function() {
            $('#overlay').on('click', function() {
                var overlay = $(this);
                $('#gallery').fadeOut(400, function() {
                    overlay.fadeOut(400);
                    $('#first-image').show().attr({
                        src: '',
                        alt: ''
                    }).siblings('img').remove();

                });

            });

        }
    },

    init: function() {
        this.fn.createGallery();
        this.fn.populateGallery();
        this.fn.showGallery();
        this.fn.navigate();
        this.fn.closeGallery();

    }
};

L'oggetto può essere inizializzato come segue:


$(function() {
    Gallery.init();
});

Analisi del codice

L'oggetto Gallery è composto da tre membri:

  1. utils – Oggetto che contiene due metodi di utility:
    1. getCurrentImage(element) – Questo metodo accetta come argomento l'elemento a che contiene l'immagine nel documento. Restituisce un oggetto che memorizza il percorso dell'immagine ed il suo attributo alt.
    2. insertOtherImages(element) – Questo metodo accetta come argomento l'elemento a corrente (che viene cliccato). Esegue un loop sugli altri elementi a (ovviamente ad eccezione di se stesso) e genera le altre immagini da inserire nella gallery dopo quella corrente.
  2. fn – Il core del nostro oggetto principale. Ha cinque metodi:
    1. createGallery() – Genera la struttura HTML della gallery e imposta l'altezza dell'overlay sull'altezza dell'intero documento.
    2. populateGallery() – Genera i link per la navigazione delle immagini con un loop attraverso i link presenti nel documento. Ciascun link avrà un attributo data-image che contiene l'indice dell'immagine corrispondente.
    3. showGallery() – Questo metodo associa un evento click ai link presenti nel documento. Per prima cosa inserisce l'immagine corrente, quindi inserisce le altre immagini. A quel punto mostra l'elemento di overlay e la gallery con un effetto di assolvenza.
    4. navigate() – Questo metodo reperisce l'indice delle immagini memorizzato nell'attributo data- e lo usa per visualizzare l'immagine corrente nella galleria, nascondendo al contempo tutte le altre.
    5. closeGallery() – Questo metodo fa sparire l'overlay e la gallery resettandone la struttura DOM.
  3. init() – Metodo di inizializzazione dell'oggetto Gallery.
Torna su