Estensioni
Indice
Lo scopo di un’estensione è di eseguire un’azione utilizzando un insieme di elementi, proprio come fanno, per esempio, i metodi fadeOut o addClass della libreria.
È possibile effettuare le proprie estensioni e usarle privatamente nel progetto o è anche possibile pubblicarli in modo che altri potranno usufruire.
(function($){ $.fn.myNewPlugin = function() { return this.each(function(){ // fare qualcosa }); }; }(jQuery));
$.fn.myNewPlugin = function() { //...
(function($){ //... }(jQuery));
Per ora, internamente l’estensione è:
$.fn.myNewPlugin = function() { return this.each(function(){ // fare qualcosa }); };
var somejQueryObject = $('#something'); $.fn.myNewPlugin = function() { alert(this === somejQueryObject); }; somejQueryObject.myNewPlugin(); // mostra un avviso con 'true'
Per interagire con l’insieme di elementi, è necessario fare un ciclo, che è facilmente ottenibile con il metodo each():
$.fn.myNewPlugin = function() { return this.each(function(){ }); };
(function($){ $.fn.showLinkLocation = function() { return this.filter('a').each(function(){ $(this).append( ' (' + $(this).attr('href') + ')' ); }); }; }(jQuery)); // Esempio di utilizzo: $('a').showLinkLocation();
<!-- Prima che l'estensione sia chiamata: --> <a href="page.html">Foo</a> <!-- Dopo che l'estensione sia chiamata: --> <a href="page.html">Foo (page.html)</a>
(function($){ $.fn.showLinkLocation = function() { return this.filter('a').append(function(){ return ' (' + this.href + ')'; }); }; }(jQuery));
Di seguito è riportato un altro eEsempio di estensione. In questo caso, non è tenuto a fare un ciclo su ogni elemento perché la funzionalità è delegata direttamente in un altro metodo di jQuery:
(function($){ $.fn.fadeInAndAddClass = function(duration, className) { return this.fadeIn(duration, function(){ $(this).addClass(className); }); }; }(jQuery)); // Esempio di utilizzo: $('a').fadeInAndAddClass(400, 'finishedFading');
Tuttavia, la qualità può variare notevolmente tra le estensioni. Molti sono ampiamente testati e ben mantenute, ma alcuni sono state create in fretta e poi ignorate, senza seguire le buone prassi.
Google è il miglior strumento per trovare le estensioni (anche se il team di jQuery sta lavorando per migliorare la sua repository di estensioni). Una volta trovata l’estensione, si consiglia di consultare la newsletter di jQuery o il canale IRC #jquery per ottenere il parere di altri circa l’estensione.
Assicurarsi che l’estensione sia ben documentata, e che offono esempi di utilizzo. Stare attenti anche con le estensioni che fanno più del necessario, queste possono arrivare a sovraccaricare la pagina. Per ulteriori suggerimenti su come individuare un’estensione mediocre, è possibile leggere l’articolo (in inglese) I segni di un plugin per jQuery scritto male da Remy Sharp (http://remysharp.com/2010/06/03/signs-of-a-poorly-written-jquery-plugin/).
Dopo aver selezionato l’estensione, è necessario aggiungerla alla pagina. In primo luogo, scaricare l’estensione, scompattarla (se necessario) e spostarla nella cartella dell’applicazione. Infine inserirla utilizzando l’elemento script (dopo l’inclusione di jQuery).
La maggior parte delle estensioni sono metodi creati all’interno del namespace $.fn. jQuery assicura che un metodo chiamato sull’oggetto jQuery sia in grado di accedere a detto oggetto attraverso this. In contrasto, l’estensione dovrebbe garantire per restituire lo stesso oggetto ricevuto (salvo diversa indicazione).
Di seguito si mostra un esempio:
8.1: Creare una estensione per aggiungere e rimuovere una clesse in un elemento quando accade l'evento hover
// definizione dell'estensione (function($){ $.fn.hoverClass = function(c) { return this.hover( function() { $(this).toggleClass(c); } ); }; })(jQuery); // utilizzare l'estensione $('li').hoverClass('hover');
In questo articolo, si sviluppa un’estensione chiamata
$.fn.hilight
, che fornisce un supporto per l’estensione metadata (se presente) e fornisce un metodo decentrato per impostare opzioni globali o istanze dell’estensione.8.2: Il modello di sviluppo di estensioni per jQuery spiegato da Mike Alsup
// // creare una chiusura // (function($) { // // definizione dell'estensione // $.fn.hilight = function(options) { debug(this); // generazione delle opzioni principali // prima di interagire var opts = $.extend({}, $.fn.hilight.defaults, options); // ittera e riformatta ogni elemento return this.each(function() { $this = $(this); // generazione delle opzioni specifiche // per ogni elemento var o = $.meta ? $.extend({}, opts, $this.data()) : opts; // aggiornamento degli stili per ogni elemento $this.css({ backgroundColor: o.background, color: o.foreground }); var markup = $this.html(); // si chiama la funzione per la formattazione markup = $.fn.hilight.format(markup); $this.html(markup); }); }; // // funzione privata per la depurazione // function debug($obj) { if (window.console && window.console.log) window.console.log('hilight selection count: ' + $obj.size()); }; // // definire ed esporre la funzione di formattazione // $.fn.hilight.format = function(txt) { return '<strong>' + txt + '</strong>'; }; // // opzioni predefinite // $.fn.hilight.defaults = { foreground: 'red', background: 'yellow' }; // // fine della chiusura // })(jQuery);
Mentre la maggior parte delle estensioni per jQuery sono esenti da manutenzione dello stato (stateless in inglese) – vale a dire, estensioni che vengono eseguiti su un solo elemento, essendo l’unica interazione – c’è un grande numero di funzionalità che non si utilizzano nello schema di base dove si sviluppano estensioni.
Per colmare questa lacuna, jQuery UI (jQuery User Interface) ha implementato un sistema più avanzato di estensioni. Questo sistema permette di gestire gli stati e ammette più funzioni da essere esposte in una singola estensione. Questo sistema è chiamato widget factory e fa parte della versione 1.8 di jQuery UI attraverso jQuery.widget, ma può essere utilizzato anche senza dipendere da jQuery UI.
Per dimostrare le capacità di widget factory, si creerà un’estensione che avrà come funzionalità sarà barra di avanzamento.
Per ora, l’estensione permetterà solo d’impostare il valore della barra di avanzamento una volta. Questo sarà fatto chiamando jQuery.widget con due parametri: il nome dell’estensione da creare e un oggetto letterale contenente le funzioni supportate. Quando l’estensione sarà chiamata, una sua istanza verrà creata e tutte le funzioni si eseguiranno nel contesto di tale istanza.
Ci sono due differenze importanti rispetto a una estensione standard per jQuery: in primo luogo, il contesto è un oggetto, non un elemento DOM; in secondo luogo, il contesto è sempre un unico oggetto, mai una collezione.
8.3: Una semplice estensione con mantenimento dello stato utilizzando widget factory di jQuery UI
$.widget("nmk.progressbar", { _create: function() { var progress = this.options.value + "%"; this.element .addClass("progressbar") .text(progress); } });
$("<div></div>") .appendTo( "body" ) .progressbar({ value: 20 });
Come si mostra sotto, è possibile specificare valori predefiniti per ogni opzione. Questi valori dovrebbero essere basati sull’uso più comune dell’estensione.
8.5: Impostare le opzioni di default per un widget
$.widget("nmk.progressbar", { // opzioni predefinite options: { value: 0 }, _create: function() { var progress = this.options.value + "%"; this.element .addClass( "progressbar" ) .text( progress ); } });
8.6: Creare metodi nel Widget
$.widget("nmk.progressbar", { options: { value: 0 }, _create: function() { var progress = this.options.value + "%"; this.element .addClass("progressbar") .text(progress); }, // crea un metodo pubblico value: function(value) { // non si passa alcun valore, // agisce quindi come metodo ottenitore (getter) if (value === undefined) { return this.options.value; // passando un valore, agisce quindi // come metodo impostatore (setter) } else { this.options.value = this._constrain(value); var progress = this.options.value + "%"; this.element.text(progress); } }, // crea un metodo privato _constrain: function(value) { if (value > 100) { value = 100; } if (value < 0) { value = 0; } return value; } });
8.7: Chiamare i metodi in un'istanza dell'estensione
var bar = $("<div></div>") .appendTo("body") .progressbar({ value: 20 }); // ottiene il valore corrente alert(bar.progressbar("value")); // aggiorna il valore bar.progressbar("value", 50); // ottiene di nuovo il valore alert(bar.progressbar("value"));
8.8: Risponde quando l'opzione è impostata
$.widget("nmk.progressbar", { options: { value: 0 }, _create: function() { this.element.addClass("progressbar"); this._update(); }, _setOption: function(key, value) { this.options[key] = value; this._update(); }, _update: function() { var progress = this.options.value + "%"; this.element.text(progress); } });
8.9: Fornire funzioni di (callback) retrochiamata
$.widget("nmk.progressbar", { options: { value: 0 }, _create: function() { this.element.addClass("progressbar"); this._update(); }, _setOption: function(key, value) { this.options[key] = value; this._update(); }, _update: function() { var progress = this.options.value + "%"; this.element.text(progress); if (this.options.value == 100) { this._trigger("complete", null, { value: 100 }); } } });
Se l’estensione avrà qualche funzionalità che potrebbero essere annullate dall’utente, il modo migliore è quello di creare funzioni di callback annullabile. L’utente può annullare una funzione di callback o il suo evento associato nello stesso modo che viene annullato qualunque evento nativo: chiamando a event.preventDefault() o usando return false.
8.10: Vincolare a eventi del widget
var bar = $("<div></div>") .appendTo("body") .progressbar({ complete: function(event, data) { alert( "Funzione di callback" ); } }) .bind("progressbarcomplete", function(event, data) { alert("Eventi bolla e molti gestori di supporto per una flessibilità estrema."); alert("Il valore della barra di avanzamento è " + data.value); }); bar.progressbar("option", "value", 100);
Perché l’istanza dell’estensione è direttamente legata all’elemento DOM, è possibile accedere all’istanza dell’estensione direttamente. Questo permette di chiamare i metodi direttamente nell’istanza dell’estensione invece di passare il nome del metodo come una stringa, dando la possibilità di accedere alle proprietà dell’estensione.
var bar = $("<div></div>") .appendTo("body") .progressbar() .data("progressbar" ); // chiamare un metodo direttamente // nell'istanza dell'estensione bar.option("value", 50); // accedere alle proprietà // nell'istanza dell'estensione alert(bar.options.value);
$.nmk.progressbar.prototype.reset = function() { this._setOption("value", 0); };
8.11: Aggiungere un metodo destroy al widget
$.widget( "nmk.progressbar", { options: { value: 0 }, _create: function() { this.element.addClass("progressbar"); this._update(); }, _setOption: function(key, value) { this.options[key] = value; this._update(); }, _update: function() { var progress = this.options.value + "%"; this.element.text(progress); if (this.options.value == 100 ) { this._trigger("complete", null, { value: 100 }); } }, destroy: function() { this.element .removeClass("progressbar") .text(""); // chiama alla funzione base destroy $.Widget.prototype.destroy.call(this); } });
$('#myTable').stripe('#cccccc');
Ancora nessun commento