Gran parte del codice che viene scritto nei plugin per jQuery è procedurale. Finchè la struttura di un plugin è relativamente semplice e le azioni da compiere sono poche, un codice procedurale è più che soddisfacente. Man mano che la complessità aumenta, scrivere funzioni su funzioni porta ad avere un codice assolutamente ingestibile. Addirittura molti plugin non suddividono il loro codice neppure nei blocchi delle funzioni, portando così ad avere un codice più simile allo "spaghetti code" che non a quello che ci si aspetterebbe da un plugin scritto per una libreria che fa dell'OOP la sua bandiera. Ci sono rimedi?
Suddividere il codice in azioni
Occorre suddividere il codice in più azioni e pensare a ciascuna azione come ad un segmento logico autonomo. Per esempio:
- Nascondere tutte le immagini eccetto la prima
- Creare uno scorrimento automatico
- Associare un'azione alle miniature dello slideshow
In un codice procedurale, queste azioni equivarrebbero ad altrettante funzioni:
(function($) {
$.fn.slider = function(options) {
var prepare = function() {
// azione 1
};
var slide = function() {
// azione 2
};
var controls = function() {
// azione 3
};
};
})(jQuery);
In realtà queste azioni appartengono ad un unico blocco logico, ossia lo slideshow, che al suo interno ha tre azioni. Nella terminologia OOP si parla di una classe/oggetto (lo slideshow) e tre metodi (tre funzioni).
Usare gli oggetti
Quindi se esiste un unico blocco logico, un unico oggetto avente azioni distinte, possiamo riscrivere il codice di cui sopra nel modo seguente:
(function($) {
$.fn.slider = function(options) {
var Slideshow = {
prepare: function() {
// azione 1
},
slide: function() {
// azione 2
},
controls: function() {
// azione 3
},
init: function() {
this.prepare();
this.slide();
this.controls();
}
};
};
})(jQuery);
In termini più ampi, l'intero plugin così come viene definito è un oggetto, perchè le funzioni sono oggetti. In questo senso stiamo utilizzando il namespace del plugin per creare al suo interno un oggetto (privato) che a sua volta crea un suo namespace.
Quindi è sufficiente una sola chiamata all'inizializzatore del nostro oggetto:
return this.each(function() {
Slideshow.init();
});
Oggetti e contesto
Possiamo rendere i nostri oggetti più flessibili fornendo loro un contesto. I plugin jQuery operano per lo più su elementi HTML. Questi elementi di solito vengono definiti nelle opzioni del plugin:
var defaults = {
wrapper: $('#slideshow-wrapper'),
speed: 800
};
options = $.extend(defaults, options);
Ecco come possiamo usare questo contesto:
var Slideshow = {
prepare: function(context) {
$('img', context).not(':first').hide();
},
//...
init: function() {
this.prepare(options.wrapper);
}
};
Esiste tuttavia un contesto più globale che appartiene all'elemento HTML principale su cui opera il plugin. Quando scriviamo:
$('div.slider').slider();
L'elemento con classe slider
è il nostro contesto globale, che possiamo identificare con la parola chiave this
:
(function($) {
$.fn.slider = functions(options) {
var context = this;
};
})(jQuery);
Possiamo quindi utilizzare questo contesto globale nel nostro oggetto:
(function($) {
$.fn.slider = functions(options) {
var context = this;
var Slideshow = {
prepare: function(cont) {
$('img', cont).not(':first').hide();
},
//...
init: function() {
this.prepare(context);
}
};
};
})(jQuery);
Otteniamo in questo modo delle azioni precise e mirate sugli elementi, che aumentano di molto la flessibilità del nostro codice.