Facendo uso di Widget Factory di jQuery UI

Per molto tempo, l'unico modo per scrivere controlli personalizzati in jQuery era estendere il $ .fn namespace. Funziona bene per i widget semplici, tuttavia, quando inizi a creare widget con più stati, diventa rapidamente ingombrante. Per facilitare il processo di creazione dei widget, il team dell'interfaccia utente di jQuery ha introdotto Widget Factory, che rimuove la maggior parte del boilerplate generalmente associato alla gestione di un widget.

La fabbrica di widget, parte del jQuery UI Core, fornisce un modo orientato agli oggetti per gestire il ciclo di vita di un widget. Queste attività del ciclo di vita includono:

  • Creazione e distruzione di un widget
  • Modifica delle opzioni del widget
  • Fabbricazione "super"chiama i widget sottoclasse
  • Notifiche di eventi

Esploriamo questa API, mentre costruiamo un semplice widget del grafico a proiettili.


Bullet Chart Widget

Prima di costruire questo widget, comprendiamo alcuni dei componenti del widget. Il Bullet Chart è un concetto introdotto da Stephen Few come variante del grafico a barre.

Il grafico consiste in un insieme di barre e marker sovrapposti l'uno sull'altro per indicare la performance relativa. Esiste una scala quantitativa per mostrare l'effettivo intervallo di valori. Impilando le barre e i contrassegni in questo modo, è possibile trasmettere più informazioni senza comprometterne la leggibilità. La leggenda dice il tipo di informazioni che stiamo tracciando.

L'HTML per questo grafico è simile al seguente:

 
Linea verde
0
25
50
75
100

Il nostro widget, che chiameremo jquery.bulletchart, genererà dinamicamente questo codice HTML dai dati forniti. Il widget finale può essere visualizzato nei file di origine, che è possibile scaricare da GitHub. La chiamata per creare il widget dovrebbe apparire così:

 $ ('. chart'). bulletchart (size: 86, bars: [title: 'Projected Target', valore: 75, css: ", title: 'Target effettivo', valore: 50, css: ' blu '], marcatori: [title:' Green Line ', valore: 80, css:' green ', title:' Minimum Threshold ', valore: 50, css:' red '], tick: [ 0, 25, 50, 75, 100]);

Tutti i valori sono in percentuale. Il taglia l'opzione può essere utilizzata quando si desidera disporre di più grafici puntati uno accanto all'altro con relativo dimensionamento. Il zecche l'opzione è usata per mettere le etichette sulla scala. I marcatori e le barre sono specificati come una matrice di valori letterali oggetto con titolo, valore e css proprietà.


Costruire il widget

Ora che conosciamo la struttura del widget, passiamo a costruirlo. Un widget viene creato chiamando $ .Widget () con il nome del widget e un oggetto contenente i suoi metodi di istanza. L'API esatta assomiglia a:

jQuery.widget (nome [, base], prototipo)

Per ora, lavoreremo solo con il nome e gli argomenti del prototipo. Per il diagramma di proiettile, il nostro stub di widget di base ha il seguente aspetto:

 $ .widget ('nt.bulletchart', opzioni: , _create: function () , _destroy: function () , _setOption: function (chiave, valore) );

Si consiglia di assegnare sempre un nome ai nomi dei widget. In questo caso, stiamo usando 'nt.bulletchart'. Tutti i widget dell'interfaccia utente jQuery sono sotto 'ui'spazio dei nomi. Sebbene si stia assegnando il nome al widget, la chiamata per creare un widget su un elemento non include lo spazio dei nomi. Quindi, per creare un grafico a proiettili, chiameremmo semplicemente $ ( '# Elem'). Bulletchart ().

Le proprietà dell'istanza vengono specificate in base al nome del widget. Per convenzione, tutti i metodi privati ​​del widget devono essere preceduti da "_". Ci sono alcune proprietà speciali che sono previste dalla fabbrica di widget. Questi includono il opzioni, _creare, _distruggere e _setOption.

  • opzioni: Queste sono le opzioni predefinite per il widget
  • _creare: La fabbrica di widget chiama questo metodo la prima volta che il widget viene istanziato. Questo è usato per creare il DOM iniziale e allegare qualsiasi gestore di eventi.
  • _dentro: Seguito alla chiamata a _creare, la fabbrica chiama _dentro. Questo è generalmente utilizzato per ripristinare il widget allo stato iniziale. Una volta creato un widget, chiamando il costruttore di widget semplice, ad esempio: $ .Bulletchart (), ripristinerà anche il widget. Questo internamente chiama _dentro.
  • _setOption: Chiamato quando si imposta un'opzione sul widget, con una chiamata come: $ ('# elem'). bulletchart ('option', 'size', 100). Più avanti vedremo altri modi per impostare le opzioni sul widget.

Creazione del DOM iniziale con _creare

Il nostro widget bulletchart prende vita in _creare metodo. Qui è dove costruiamo la struttura di base per il grafico. Il _creare la funzione può essere vista sotto. Noterai che qui non sta accadendo molto oltre alla creazione del contenitore di livello superiore. Il vero lavoro di creare il DOM per barre, marker e tick avviene nel _setOption metodo. Questo può sembrare un po 'contro-intuitivo per cominciare, ma c'è una ragione valida per quello.

 _create: function () this.element.addClass ('bullet-chart'); // contenitore grafico this._container = $ ('
') .appendTo (this.element); this._setOptions ('size': this.options.size, 'ticks': this.options.ticks, 'bars': this.options.bars, 'markers': this.options.markers);

Nota che le barre, i contrassegni e le zecche possono anche essere modificati impostando le opzioni sul widget. Se tenevamo il codice per la sua costruzione all'interno _creare, ci ripeteremo dentro _setOption. Spostando il codice in _setOption e invocandolo da _creare rimuove la duplicazione e centralizza anche la costruzione.

Inoltre, il codice sopra mostra un altro modo di impostare le opzioni sul widget. Con il _setOptions metodo (si noti il ​​plurale), è possibile impostare le opzioni mutiple in un colpo solo. Internamente, la fabbrica effettuerà chiamate individuali _setOption per ciascuna delle opzioni.

Il _setOption metodo

Per il grafico proiettile, il _setOption il metodo è il cavallo di battaglia. Gestisce la creazione di marcatori, barre e zecche e anche eventuali modifiche apportate a queste proprietà. Funziona cancellando tutti gli elementi esistenti e ricreandoli in base al nuovo valore.

Il _setOption il metodo riceve sia la chiave di opzione che un valore come argomenti. La chiave è il nome dell'opzione, che dovrebbe corrispondere a uno dei tasti nelle opzioni predefinite. Ad esempio, per modificare le barre sul widget, si effettuerà la seguente chiamata:

$ ('# elem'). bulletchart ('option', 'bars', [title: 'New Marker', valore: 50]))

Il _setOption il metodo per il diagramma di progetto è simile al seguente:

 _setOption: function (chiave, valore) var self = this, prev = this.options [chiave], fnMap = 'bars': function () createBars (value, self); , 'marcatori': function () createMarkers (valore, self); , 'ticks': function () createTickBar (valore, self); , 'size': function () self.element.find ('. chart-container') .css ('width', value + '%'); ; // base this._super (chiave, valore); if (digita fnMap) fnMap [key] (); // Evento Fire this._triggerOptionChanged (chiave, anteprima, valore); 

Qui, creiamo un semplice hash del nome-opzione per la funzione corrispondente. Usando questo hash, lavoriamo solo su opzioni valide e ignoriamo silenziosamente quelli non validi. Ci sono altre due cose che accadono qui: una chiamata a _super() e sparando l'opzione ha cambiato evento. Li esamineremo più avanti in questo articolo.

Per ciascuna delle opzioni che cambia il DOM, chiamiamo un metodo di supporto specifico. I metodi di supporto, createBars, createMarkers e createTickBar sono specificati al di fuori delle proprietà dell'istanza del widget. Questo perché sono gli stessi per tutti i widget e non è necessario che siano creati individualmente per ogni istanza del widget.

// Funzione funzioni di creazione createTickBar (tick, widget) // Cancella widget._container.find esistente ('. Tick-bar'). Remove (); var tickBar = $ ('
'); $ .each (tick, funzione (idx, tick) var t = $ ('
') .css (' left ', tick +'% '); var tl = $ ('
') .css (' left ', tick +'% ') .text (tick); tickBar.append (t); tickBar.append (tl); ); widget._container.append (tickBar); function createMarkers (marker, widget) // Cancella widget._container.find esistente ('. marker'). remove (); $ .each (marcatori, funzione (idx, m) var marker = $ ('
') .css (left: m.value +'% ') .addClass (m.css) .attr (' marker-index ', idx); widget._container.append (marker); ); function createBars (bars, widget) // Cancella widget._container.find esistente ('. bar'). remove (); $ .each (barre, funzione (idx, barra) var bar = $ ('
') .css (left: 0, width:' 0% ') .addClass (bar.css) .attr (' bar-index ', idx) .animate (width: bar.value +'% ' ); widget._container.append (bar); );

Tutte le funzioni di creazione operano su percentuali. Ciò garantisce che il grafico si rifletta bene quando ridimensioni l'elemento contenitore.

Le opzioni predefinite

Senza le opzioni specificate durante la creazione del widget, entrano in gioco le impostazioni predefinite. Questo è il ruolo del opzioni proprietà. Per il diagramma di proiettile, le nostre opzioni di default sono così:

 $ .widget ('nt.bulletchart', options: // percentage: 0 - 100 size: 100, // [title: 'Sample Bar', valore: 75, css: "], barre: [] , // [title: 'Sample Marker', valore: 50, css: "], marker: [], // ticks - valori percentuali tick: [0, 10, 20, 30, 40, 50, 60 , 70, 80, 90, 100], ...

Iniziamo con una dimensione di 100%, niente barre e marcatori e con tick piazzati ogni 10%. Con questi valori predefiniti, il nostro grafico a proiettili dovrebbe essere simile a:

Finora, abbiamo visto come creare il widget usando _creare e aggiornandolo usando _setOption. Esiste un altro metodo del ciclo di vita, che verrà chiamato quando si distrugge un widget. Questo è il _distruggere metodo. Quando chiami $ ( '# Elem'). Bulletchart ( 'distruggere'), la fabbrica di widget chiama internamente _distruggere sull'istanza del widget. Il widget è responsabile della rimozione di tutto ciò che ha introdotto nel DOM. Questo può includere classi e altri elementi DOM aggiunti in _creare metodo. Questo è anche un buon posto per dissipare qualsiasi gestore di eventi. Il _distruggere dovrebbe essere l'esatto opposto del _creare metodo.

Per il widget del grafico a proiettile, il _distruggere è abbastanza semplice:

 _destroy: function () this.element.removeClass ('bullet-chart'); this.element.empty (); ,

Sottoclassi, eventi e altro

Il nostro widget bulletchart è quasi completo, tranne un'ultima funzione: leggenda. La leggenda è abbastanza essenziale, poiché darà più significato ai marcatori e alle barre. In questa sezione aggiungeremo una legenda accanto al grafico.

Piuttosto che aggiungere questa funzione direttamente al widget del diagramma di proiettile, creeremo una sottoclasse, bulletchart2, che avrà il supporto della leggenda. Nel processo, esamineremo anche alcune delle caratteristiche interessanti dell'ereditarietà di Widget Factory.

Aggiungere una legenda

The Widget Factory supporta la sottoclasse di un widget per creare versioni più specializzate. All'inizio dell'articolo, abbiamo visto l'API per $ .Widget (), che aveva tre argomenti:

jQuery.widget (nome [, base], prototipo)

Il secondo parametro ci consente di scegliere una classe base per il nostro widget. Nostro bulletchart2 widget, che sottoclasse bulletchart, avrà la seguente firma:

 $ .widget ('nt.bulletchart2', $ .nt.bulletchart, options: // Mostra / nascondi legenda della legenda: true, // questo ci assicura di mantenere lo stesso spazio dei nomi del widget baseEventPrefix: $ .nt.bulletchart .prototype.widgetEventPrefix, _create: function () ..., _destroy: function () ..., _setOption: function (chiave, valore) ...)

Ci sono alcune cose interessanti da notare qui:

  • Continuiamo a namespace il nome del nostro widget: nt.bulletchart2.
  • La fabbrica di widget mette automaticamente il widget sotto il $ .NT namespace. Quindi, per fare riferimento al nostro widget precedente, abbiamo usato $ .nt.bulletchart. Allo stesso modo, se dovessimo creare una sottoclasse di uno dei widget standard dell'interfaccia utente di jQuery, faremo riferimento a loro $ .Ui.widget-nome
  • Il widgetEventPrefix è una nuova proprietà che non abbiamo mai visto prima. Ci arriveremo quando parliamo di eventi. Il resto delle proprietà dell'istanza dovrebbe essere familiare.

Dato che stiamo aggiungendo altri elementi DOM con la legenda, dovremo ignorare il _creare metodo. Ciò significa anche che dobbiamo scavalcare _distruggere, per essere simmetrici.

 _create: function () var self = this; this._legend = $ ('
') .appendTo (this.element); ... // Chiama la base this._super (); this._setOption ('legend', this.options.legend); , _destroy: function () this.element.find ('. legend'). empty (); ... this._super (); ,

Qui, di nuovo, vediamo lo stesso schema del nostro precedente _creare metodo. Creiamo il contenitore per la legenda e poi chiamiamo _setOption per costruire il resto della leggenda. Dal momento che stiamo ignorando il _creare, dobbiamo assicurarci di chiamare la base _creare. Lo facciamo con la chiamata a _super. Allo stesso modo, in _distruggere, vediamo anche la chiamata a _super.

Ora ti starai chiedendo: come fa il widget a sapere quale super-metodo chiamare con un semplice non qualificato _super invocazione? L'intelligenza per quello si trova nelle viscere della fabbrica di widget. Quando un widget è sottoclasse, la fabbrica imposta il _super riferimento diverso per ciascuna delle funzioni di istanza. Quindi, quando chiami _super dal tuo metodo di istanza, punta sempre al corretto _super metodo.

Notifiche di eventi

Poiché il diagramma di proiettili supporta la modifica di indicatori e barre, la legenda deve essere sincronizzata con tali modifiche. Inoltre, supporterà anche la commutazione della visibilità di marcatori e barre facendo clic sugli elementi della legenda. Questo diventa utile quando hai diversi indicatori e barre. Nascondendo alcuni elementi, puoi vedere gli altri più chiaramente.

Per supportare la sincronizzazione della legenda con le modifiche ai marcatori e alle barre, il file bulletchart2 il widget deve ascoltare i cambiamenti che si verificano su tali proprietà. Il bulletchart di base genera già un evento di modifica ogni volta che le sue opzioni cambiano. Ecco lo snippet corrispondente dal widget di base:

 _setOption: function (chiave, valore) var self = this, prev = this.options [chiave]; ... // base this._super (chiave, valore); if (digita fnMap) fnMap [key] (); // Evento Fire this._triggerOptionChanged (chiave, anteprima, valore); , _triggerOptionChanged: function (optionKey, previousValue, currentValue) this._trigger ('setOption', type: 'setOption', opzione: optionKey, precedente: previousValue, current: currentValue); 

Ogni volta che viene impostata un'opzione, il setOption l'evento è licenziato. I dati dell'evento contengono il valore precedente e il nuovo dell'opzione che è stata modificata.

Ascoltando questo evento nel widget sottoclasse, puoi sapere quando cambiano i marker o le barre. Il bulletchart2 widget si iscrive a questo evento nel suo _creare metodo. L'iscrizione agli eventi widget si ottiene con la chiamata a this.element.on (). this.element punta all'elemento jQuery su cui è stato istanziato il widget. Dato che l'evento sarà attivato sull'elemento, il nostro abbonamento all'evento deve avvenire su questo.

 _create: function () var self = this; this._legend = $ ('
') .appendTo (this.element); ... // Applica la legenda alle modifiche ai marcatori e alle barre this.element.on (' bulletchart: setoption ', function (event, data) if (data.option ===' markers ') createLegend (data.current, self.options.bars, self); else if (data.option ===' bars ') createLegend (self.options.markers, data.current, self); ); // Chiama la base this._super (); this._setOption ('legend', this.options.legend);

Nota il nome dell'evento utilizzato per la sottoscrizione: 'Bulletchart: SetOption'. Come criterio, il factory dei widget allega un prefisso evento per gli eventi attivati ​​dal widget. Per impostazione predefinita, questo prefisso è il nome del widget, ma può essere facilmente modificato con widgetEventPrefix proprietà. Il widget di base del diagramma di controllo lo modifica 'Bulletchart:'.

$ .widget ('nt.bulletchart', options: ..., widgetEventPrefix: 'bulletchart:' ...);

Dobbiamo anche abbonarci a 'clic' eventi sulle voci della legenda per nascondere / mostrare il corrispondente indicatore / barra. Lo facciamo con il _sopra metodo. Questo metodo accetta un hash della firma dell'evento nella funzione del gestore. Il contesto del gestore (Questo) è impostato correttamente sull'istanza del widget. Un'altra comodità con _sopra è che la fabbrica di widget smantella automaticamente gli eventi su destroy.

 _create: function () ... // Ascolta i clic sulla legenda-item this._on ('click .legend-item': function (event) var elt = $ (event.currentTarget), item = elt.data ('chart-item'), selector = '[' + item.type + '-index =' + item.index + ']'; this.element.find (selector) .fadeToggle (); elt.toggleClass (' dissolvenza ');); ...

Più suggerimenti

La fabbrica di Widget racchiude alcune altre sottigliezze di cui dovresti essere a conoscenza.

Fare riferimento all'istanza del widget

Finora, abbiamo visto solo un modo di chiamare metodi sul widget. Abbiamo fatto questo con $ ( '# Elem) .bulletchart (' metodo-name '). Tuttavia, questo consente solo di chiamare metodi pubblici come "option", "destroy", "on", "off". Se si desidera richiamare tali metodi direttamente sull'istanza del widget, esiste un modo per farlo. La fabbrica di widget collega l'istanza del widget al dati() oggetto dell'elemento. Puoi ottenere questa istanza in questo modo:

var widget = $ ('# elem'). data ('bulletchart'); widget.destroy ();

Inoltre, se si desidera ottenere una sospensione di tutti i widget di bulletchart sulla pagina, esiste anche un selettore per questo:

var allCharts = $ (': nt-bulletchart');

Alcuni metodi speciali

Ci sono alcuni metodi speciali di cui dovresti essere a conoscenza, che vengono usati meno frequentemente: _getCreateEventData () e _getCreateOptions (). Il primo viene utilizzato per allegare i dati dell'evento per l'evento "create" che viene generato dopo aver terminato la chiamata _creare.

_getCreateOptions è per allegare opzioni predefinite aggiuntive per il widget o per sovrascrivere quelle esistenti. Le opzioni fornite dall'utente sostituiscono le opzioni restituite da questo metodo, che a sua volta sostituisce le opzioni del widget predefinito.


Sommario

Questo è un involucro! Se vuoi approfondire ulteriormente, i riferimenti qui sotto dovrebbero servire abbastanza bene. Ovviamente, la migliore fonte di informazione sarà sempre il codice sorgente, di per sé. Vorrei incoraggiare la lettura della sorgente jquery.ui.widget su GitHub.

  • API JQueryUI Widget Factory
  • Diapositive su Widget Factory