Gjør bruk av jQuery UI's Widget Factory

I lang tid var den eneste måten å skrive tilpassede kontroller i jQuery å forlenge $ .fn navnerom. Dette fungerer bra for enkle widgets, men når du begynner å bygge mer stateful widgets, blir det raskt besværlig. For å hjelpe til med å bygge widgets, introduserte jQuery UI-teamet Widget Factory, som fjerner det meste av kjelen som vanligvis er knyttet til å administrere en widget.

Widget fabrikken, en del av jQuery UI Core, gir en objektorientert måte å styre livscyklusen til en widget på. Disse livscyklusaktivitetene inkluderer:

  • Opprette og ødelegge en widget
  • Endre widgetalternativer
  • Lager "super"samtaler i subclassed widgets
  • Hendelsesvarsler

La oss utforske denne API-en, da vi bygger en enkel bullet-diagram-widget.


The Bullet Chart Widget

Før vi bygger denne widgeten, la oss forstå noen av byggeblokkene i widgeten. Bullet-diagrammet er et konsept introdusert av Stephen Few som en variasjon på linjediagrammet.

Diagrammet består av et sett med barer og markører som er lagt på hverandre for å indikere relativ ytelse. Det er en kvantitativ skala for å vise det faktiske utvalg av verdier. Ved å stable stengene og markørene på denne måten, kan mer informasjon bli formidlet uten å svekke lesbarheten. Legenden forteller hvilken type informasjon vi planlegger.

HTML for dette diagrammet ser slik ut:

 
Grønn linje
0
25
50
75
100

Vår widget, som vi vil ringe jquery.bulletchart, vil dynamisk generere denne HTML-en fra de oppgitte dataene. Den endelige widgeten kan ses i kildefilene, som du kan laste ned fra GitHub. Anropet til å lage widgeten skal se slik ut:

 $ 'chart'). bulletchart (størrelse: 86, barer: [title: 'Projected Target', verdi: 75, css: ", tittel: 'Actual Target', verdi: 50, css: ' blå '], markører: [tittel:' Grønn linje ', verdi: 80, css:' grønn ', tittel:' Minimumterskel ', verdi: 50, css:' rød '] 0, 25, 50, 75, 100]);

Alle verdiene er i prosent. De størrelse Alternativet kan brukes når du vil ha flere punktdiagrammer plassert ved siden av hverandre med relativ dimensjonering. De flått alternativet brukes til å sette etikettene på skalaen. Markørene og linjene er angitt som en rekke objekt-bokstaver med tittel, verdi og css eiendommer.


Byg widgeten

Nå som vi kjenner strukturen til widgeten, la oss komme ned for å bygge den. En widget er opprettet ved å ringe $ .Widget () med navnet på widgeten og et objekt som inneholder sine forekomstmetoder. Den nøyaktige API ser ut som:

jQuery.widget (navn [, base], prototype)

For nå vil vi jobbe med bare navn og prototype argumenter. For bulletchart ser vår grunnleggende widgetstub ut som følgende:

 $ .widget ('nt.bulletchart', options: , _create: function () , _destroy: funksjon () , _setOption: funksjon (nøkkel, verdi) );

Det anbefales at du alltid navngir dine widgetnavn. I dette tilfellet bruker vi "nt.bulletchart'. Alle jQuery-brukergrensesnittene er under "ui'navneområde. Selv om vi navngir widgeten, inneholder ikke samtalen for å opprette en widget på et element navneområdet. For å lage et kuleplan, ville vi bare ringe $ ( '# ELEM'). Bulletchart ().

Instansegenskapene er spesifisert etter navnet på widgeten. Ved konvensjon bør alle private metoder i widgeten prefikses med '_'. Det er noen spesielle egenskaper som forventes av widgetfabrikken. Disse inkluderer opsjoner, _skape, _ødelegge og _setOption.

  • opsjoner: Dette er standardvalgene for widgeten
  • _skape: Widgetfabrikken kaller denne metoden første gang widgeten er instantiated. Dette brukes til å lage den opprinnelige DOM og legge ved eventuelle hendelseshåndterere.
  • _i det: Etter samtalen til _skape, fabrikken ringer _i det. Dette brukes vanligvis til å tilbakestille widgeten til opprinnelig tilstand. Når en widget er opprettet, ringer du den enkle widget-konstruktøren, for eksempel: $ .Bulletchart (), vil også tilbakestille widgeten. Dette ringer internt _i det.
  • _setOption: Kalt når du angir et alternativ på widgeten, med en samtale som: $ ('# elem'). bulletchart ('alternativ', 'størrelse', 100). Senere ser vi andre måter å sette inn alternativer på widgeten.

Oppretter den første DOM med _skape

Vår bulletchart-widget kommer til liv i _skape metode. Her er hvor vi bygger grunnstrukturen for diagrammet. De _skape funksjonen kan ses nedenfor. Du vil legge merke til at det ikke skjer mye her, i tillegg til å skape toppnivåbeholderen. Det faktiske arbeidet med å opprette DOM for barer, markører og flått skjer i _setOption metode. Dette kan virke litt motintuitivt å begynne med, men det er en gyldig grunn til det.

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

Legg merke til at stolpene, markørene og flåttene også kan endres ved å sette inn alternativer på widgeten. Hvis vi holdt koden for sin konstruksjon inni _skape, Vi ville gjenta oss selv inne _setOption. Ved å flytte koden til _setOption og påberope det fra _skape fjerner duplisering og sentraliserer også konstruksjonen.

I tillegg viser koden ovenfor en annen måte å sette inn alternativer på widgeten. Med _setOptions metode (noter flertallet), kan du sette mulige alternativer på en gang. Internt vil fabrikken foreta individuelle anrop _setOption for hver av alternativene.

De _setOption metode

For punktdiagrammet, _setOption Metoden er arbeidshesten. Den håndterer opprettelsen av markører, barer og flått og også eventuelle endringer som gjøres til disse egenskapene. Det fungerer ved å rydde eventuelle eksisterende elementer og gjenskape dem basert på den nye verdien.

De _setOption Metoden mottar både alternativtasten og en verdi som argumenter. Nøkkelen er navnet på alternativet, som skal svare til en av tastene i standardvalgene. Hvis du for eksempel vil endre stengene på widgeten, vil du gjøre følgende samtale:

$ ('# elem'). bulletchart ('alternativ', 'barer', [tittel: 'Ny markør', verdi: 50])

De _setOption Metoden for bulletchart ser slik ut:

 _setOption: funksjon (nøkkel, verdi) var selv = dette, prev = this.options [key], fnMap = 'bars': funksjon () createBars (verdi, selv); , 'markører': funksjon () createMarkers (verdi, selv); , 'ticks': funksjon () createTickBar (verdi, selv); , 'size': funksjon () self.element.find ('chart-container') .css ('bredde', verdi + '%'); ; // base this._super (nøkkel, verdi); hvis (tast inn fnMap) fnMap [key] (); // Brannhendelse this._triggerOptionChanged (nøkkel, tidligere, verdi); 

Her oppretter vi en enkel hash av alternativnavnet til den tilsvarende funksjonen. Ved hjelp av denne hashen jobber vi bare med gyldige alternativer og ignorerer stille ugyldige. Det er to ting som skjer her: en samtale til _super() og skyte alternativet endret hendelse. Vi vil se på dem senere i denne artikkelen.

For hver av alternativene som endrer DOM, kaller vi en bestemt hjelpemetode. Hjelpermetodene, createBars, createMarkers og createTickBar er spesifisert utenfor widget-instansegenskapene. Dette skyldes at de er de samme for alle widgets og ikke trenger å bli opprettet individuelt for hver widget-forekomst.

// Creation funksjoner funksjon createTickBar (flått, widget) // Fjern eksisterende widget._container.find ('. Tick-bar'). Fjern (); var tickBar = $ ('
'); $ .each (flått, funksjon (idx, tick) var t = $ ('
') .css (' left ', tick +'% '); var tl = $ ('
') .css (' left ', tick +'% ') .text (tick); tickBar.append (t); tickBar.append (tl); ); widget._container.append (tickBar); funksjon createMarkers (markører, widget) // Fjern eksisterende widget._container.find ('.markør'). fjern (); $ .each (markører, funksjon (idx, m) varemarkør = $ ('
') .css (left: m.value +'% ') .addClass (m.css) .attr (' markør-indeks ', idx); widget._container.append (markør); ); funksjonen createBars (barer, widget) // Fjern eksisterende widget._container.find ('.bar'). fjern (); $ .each (barer, funksjon (idx, bar) var bar = $ ('
') .css (left: 0, width:' 0% ') .addClass (bar.css) .attr (' bar-index ', idx) .animate (width: bar.value +'% ' ); widget._container.append (bar); );

Alle etableringsfunksjonene opererer på prosenter. Dette sikrer at diagrammet reflekterer pent når du endrer størrelsen på det inneholdende elementet.

Standardalternativene

Uten noen alternativer angitt når du lager widgeten, vil standardene komme inn i spill. Dette er rollen til opsjoner eiendom. For bulletchart ser standardinnstillingene ut slik:

 $ .widget ('nt.bulletchart', alternativer: // prosentandel: 0-100 størrelse: 100, // [tittel: 'Eksempelboks', verdi: 75, css: "], , // [title: 'Sample Marker', verdi: 50, css: "], markører: [], // ticks - prosentverdier flått: [0, 10, 20, 30, 40, 50, 60 , 70, 80, 90, 100], ...

Vi starter med en størrelse på 100%, ingen barer og markører og med flått plassert hver 10%. Med disse standardene, bør vårt kulebilde se ut som:

Så langt har vi sett hvordan å lage widgeten ved hjelp av _skape og oppdaterer den ved hjelp av _setOption. Det er en annen livscyklusmetode, som vil bli kalt når du ødelegger en widget. Dette er _ødelegge metode. Når du ringer $ ( '# ELEM'). Bulletchart ( 'ødelegge'), Widget fabrikken samtaler internt _ødelegge på din widget-instans. Widgeten er ansvarlig for å fjerne alt det introduserte i DOM. Dette kan inkludere klasser og andre DOM-elementer som ble lagt til i _skape metode. Dette er også et godt sted å knytte alle hendelseshåndterere til. De _ødelegge bør være det nøyaktige motsatt av _skape metode.

For punktdiagram-widgeten, vil _ødelegge er ganske enkelt:

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

Underklasse, hendelser og mer

Vår widget for bulletchart er nesten fullstendig, med unntak av en siste funksjon: legende. Legenden er ganske viktig, siden det vil gi mer mening til markørene og stolpene. I denne delen legger vi til en legende ved siden av diagrammet.

I stedet for å legge denne funksjonen direkte til bulletchart-widgeten, oppretter vi en underklasse, bulletchart2, det vil ha legenden støtte. I prosessen vil vi også se på noen av de interessante funksjonene i Widget Factory arv.

Legge til en legende

Widget Factory støtter underklasser av en widget for å skape mer spesialiserte versjoner. Tidligere i artikkelen så vi API for $ .Widget (), som hadde tre argumenter:

jQuery.widget (navn [, base], prototype)

Den andre parameteren tillater oss å velge en grunnklasse for vår widget. Våre bulletchart2 widget, hvilke underklasser bulletchart, vil ha følgende signatur:

 $ .widget ('nt.bulletchart2', $ .nt.bulletchart, options: // Vis / skjul legenden legenden: true, // dette sikrer at vi beholder samme navneområde som base widgetEventPrefix: $ .nt.bulletchart .prototype.widgetEventPrefix, _create: function () ..., _destroy: funksjon () ..., _setOption: funksjon (nøkkel, verdi) ...)

Det er noen interessante ting å merke seg her:

  • Vi fortsetter å navneområdet vårt widgetnavn: nt.bulletchart2.
  • Widget-fabrikken legger automatisk widgeten under $ .nt navnerom. Således, for å referere til vår tidligere widget, brukte vi $ .nt.bulletchart. På samme måte hvis vi skulle underklasse en av standard jQuery UI-widgets, ville vi referere dem til $ .Ui.widget-navn
  • De widgetEventPrefix er en ny eiendom som vi ikke har sett før. Vi kommer til det når vi snakker om hendelser. Resten av instansegenskapene skal være kjent.

Siden vi legger til flere DOM-elementer med legenden, må vi overstyre _skape metode. Dette betyr også at vi må overstyre _ødelegge, for å være symmetrisk.

 _create: function () var self = this; this._legend = $ ('
') .appendTo (this.element); ... // Ring basen this._super (); this._setOption ('legend', this.options.legend); , _destroy: funksjon () this.element.find ('legend'). tom (); ... this._super (); ,

Her ser vi igjen det samme mønsteret som vår tidligere _skape metode. Vi lager beholderen for legenden og deretter ring _setOption å bygge resten av legenden. Siden vi overstyrer _skape, Vi må sørge for at vi kaller basen _skape. Vi gjør dette med anropet til _super. Tilsvarende, i _ødelegge, vi ser også anropet til _super.

Nå kan du kanskje lure på: hvordan kjenner widgeten hvilken supermetode som skal ringes med en enkel, ukvalifisert _super påkalling? Smarts for det ligger i tarmene til widgetfabrikken. Når en widget er underklasse, setter fabrikken opp _super referanse forskjellig for hver av instansfunksjonene. Dermed når du ringer _super fra din instansmetode peker det alltid på det riktige _super metode.

Hendelsesvarsler

Siden bulletchart støtter skiftende markører og barer, må legenden synkronisere med disse endringene. I tillegg vil vi også støtte å bytte synlighet av markører og barer ved å klikke på legendeelementene. Dette blir nyttig når du har flere markører og barer. Ved å gjemme noen av elementene, kan du se de andre tydeligere.

For å støtte synkronisering av legenden med endringene til markører og barer, vil bulletchart2 widget må lytte til eventuelle endringer som skjer med disse egenskapene. Basen bulletchart fyrer allerede en endringshendelse hver gang alternativene endres. Her er den tilsvarende koden fra grunngjengen:

 _setOption: funksjon (nøkkel, verdi) var selv = dette, prev = this.options [key]; ... // base this._super (nøkkel, verdi); hvis (tast inn fnMap) fnMap [key] (); // Brannhendelse this._triggerOptionChanged (nøkkel, tidligere, verdi);  

Når et alternativ er satt, vil setOption hendelsen er sparken. Hendelsesdataene inneholder forrige og nye verdi for alternativet som ble endret.

Ved å lytte til denne hendelsen i den subclassed-widgeten, kan du vite når markørene eller stolpene endres. De bulletchart2 widget abonnerer på denne hendelsen i sin _skape metode. Abonnement på widgets hendelser oppnås med anropet til this.element.on (). this.element peker på jQuery-elementet som widgeten ble instansert på. Siden hendelsen blir sparket på elementet, må vårt arrangementsabonnement skje på det.

 _create: function () var self = this; this._legend = $ ('
') .appendTo (this.element); ... // Bruk legenden om endringer i markører og barer this.element.on (' bulletchart: setoption ', funksjon (event, data) if (data.option ===' markører ') createLegend (data.current, self.options.bars, self); else if (data.option ===' barer ') createLegend (self.options.markers, data.current, self); ); // Ring basen this._super (); this._setOption ('legend', this.options.legend);

Legg merke til hendelsesnavnet som brukes til å abonnere: 'Bulletchart: setoption'. Som en policy legger widgetfabrikken et hendelse-prefiks for hendelser sparket fra widgeten. Som standard er dette prefikset navnet på widgeten, men dette kan enkelt endres med widgetEventPrefix eiendom. Basis bulletchart-widgeten endrer dette til 'Bulletchart:'.

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

Vi må også abonnere på 'Klikk' hendelser på legendeelementene for å skjule / vise den tilhørende markøren / linjen. Vi gjør dette med _på metode. Denne metoden tar en hash av hendelses signaturen til håndteringsfunksjonen. Handlerens kontekst (dette) er riktig satt til widget-forekomsten. En annen bekvemmelighet med _på er at widgetfabrikken automatisk binder hendelsene til ødeleggelse.

 _create: function () ... // Lytt til klikk på legend-elementene this._on ('klikk .legend-item': funksjon (hendelse) var elt = $ (event.currentTarget), item = elt.data ('diagram-element'), selector = '[' + item.type + '-index =' + item.index + ']'; this.element.find (selector) .fadeToggle (); elt.toggleClass fade ');); ...

Flere tips

Widget-fabrikken pakker et par andre niceties som du bør være oppmerksom på.

Henvisning av widget-forekomsten

Så langt har vi bare sett en måte å ringe metoder på widgeten på. Vi gjorde dette med $ ( '# Elem) .bulletchart (' metode-navn '). Dette tillater imidlertid bare å kalle offentlige metoder som "alternativ", "ødelegge", "på", "av". Hvis du vil bruke disse metodene direkte på widget-forekomsten, er det en måte å gjøre det på. Widgetfabrikken legger til widget-forekomsten til data() objektet til elementet. Du kan få denne forekomsten som:

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

I tillegg, hvis du vil få tak i alle bulletchart-widgets på siden, er det også en valg for det:

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

Noen spesielle metoder

Det er noen spesielle metoder som du bør være oppmerksom på, som brukes sjeldnere: _getCreateEventData () og _getCreateOptions (). Den førstnevnte brukes til å knytte hendelsesdata til "opprett" -hendelsen som avfyres etter at samtalen er fullført _skape.

_getCreateOptions er for å legge til ekstra standardalternativer for widgeten eller tvingende eksisterende. De bruksmulighetene som tilbys, overstyrer alternativene som returneres av denne metoden, som i sin tur overstyrer standard widget-alternativene.


Sammendrag

Det er en vikle! Hvis du ønsker å utforske videre, bør referansene nedenfor tjene deg ganske bra. Selvfølgelig vil den beste kilden til informasjon alltid være kildekoden, selv. Jeg vil oppfordre til å lese jquery.ui.widget-kilden på GitHub.

  • JQueryUI Widget Factory API
  • Lysbilder på Widget Factory