Lange tijd was de enige manier om aangepaste besturingselementen in jQuery te schrijven, het uitbreiden van $ .fn
namespace. Dit werkt echter goed voor eenvoudige widgets, maar wanneer u meer stateful widgets gaat maken, wordt het snel omslachtig. Om het bouwen van widgets te ondersteunen, heeft het jQuery UI-team de Widget Factory geïntroduceerd, die het grootste deel van de boilerplate verwijdert die meestal wordt geassocieerd met het beheren van een widget.
De widgetfabriek, onderdeel van de jQuery UI Core, biedt een objectgeoriënteerde manier om de levenscyclus van een widget te beheren. Deze levenscyclusactiviteiten omvatten:
Laten we deze API verkennen, terwijl we een eenvoudige bullet-grafiekwidget bouwen.
Voordat we deze widget bouwen, zullen we enkele bouwstenen van de widget begrijpen. De Bullet Chart is een concept geïntroduceerd door Stephen Few als een variatie op het staafdiagram.
Het diagram bestaat uit een reeks staafjes en markeringen die over elkaar zijn gelegd om de relatieve prestaties aan te geven. Er is een kwantitatieve schaal om het werkelijke bereik van waarden te tonen. Door de staven en markeringen op deze manier te stapelen, kan meer informatie worden overgebracht zonder de leesbaarheid in gevaar te brengen. De legenda vertelt het soort informatie dat we plotten.
De HTML voor deze grafiek ziet er als volgt uit:
Groene lijn0255075100
Onze widget, die we zullen bellen jquery.bulletchart
, zal deze HTML dynamisch genereren op basis van de verstrekte gegevens. De laatste widget kan worden bekeken in de bronbestanden, die u kunt downloaden van GitHub. De aanroep om de widget aan te maken zou er zo uit moeten zien:
$ ('. chart'). bulletchart (size: 86, bars: [title: 'Projected Target', value: 75, css: ", title: 'Actual Target', value: 50, css: ' blauw '], markeringen: [title:' Green Line ', waarde: 80, css:' green ', title:' Minimum Threshold ', waarde: 50, css:' red '], teken: [ 0, 25, 50, 75, 100]);
Alle waarden zijn in percentages. De grootte
optie kan worden gebruikt wanneer u verschillende opsommingstekens naast elkaar wilt plaatsen met relatieve grootte. De teken
optie wordt gebruikt om de labels op de schaal te zetten. De markeringen en balken worden gespecificeerd als een reeks objectliteralen met titel
, waarde
en css
eigenschappen.
Nu we de structuur van de widget kennen, gaan we aan de slag met het bouwen ervan. Een widget wordt gemaakt door te bellen $ .Widget ()
met de naam van de widget en een object dat de instantiemethoden bevat. De exacte API ziet er als volgt uit:
jQuery.widget (naam [, basis], prototype)
Voor nu werken we alleen met de argumenten voor naam en prototype. Voor de bulletchart ziet onze standaard widgetstub er als volgt uit:
$ .widget ('nt.bulletchart', options: , _create: function () , _destroy: function () , _setOption: function (key, value) );
Het wordt aanbevolen dat u altijd de naam van uw widget naamruimte. In dit geval gebruiken we 'nt.bulletchart'. Alle jQuery UI-widgets vallen onder de 'ui'naamruimte. Hoewel we de widget namespacen, bevat de aanroep om een widget op een element te maken de namespace niet. Dus, om een opsommingsteken te maken, zouden we gewoon bellen $ ( '# Elem'). Bulletchart ()
.
De instantie-eigenschappen worden opgegeven volgens de naam van de widget. Volgens afspraak moeten alle privémethoden van de widget worden voorafgegaan door '_'. Er zijn enkele speciale eigenschappen die worden verwacht door de widgetfabriek. Deze omvatten de opties
, _create
, _vernietigen
en _setOption
.
opties
: Dit zijn de standaardopties voor de widget_create
: De widgetfabriek roept deze methode op wanneer de widget voor het eerst wordt geïnstantieerd. Dit wordt gebruikt om de initiële DOM te maken en eventhandlers toe te voegen._in het
: Na de oproep naar _create
, de fabrieksoproepen _in het
. Dit wordt over het algemeen gebruikt om de widget opnieuw in te stellen naar de beginstatus. Zodra een widget is gemaakt, roept u de eenvoudige widgetconstructor aan, bijvoorbeeld: $ .Bulletchart (), zal ook de widget resetten. Dit roept intern _in het
._setOption
: Bellen wanneer u een optie op de widget instelt, met een oproep zoals: $ ('# elem'). bulletchart ('option', 'size', 100)
. Later zullen we andere manieren zien om opties in de widget in te stellen._create
Onze bulletchart-widget komt tot leven in de _create
methode. Hier bouwen we de basisstructuur voor de grafiek. De _create
functie is hieronder te zien. U zult merken dat er niet veel gebeurt hier naast het creëren van de container op het hoogste niveau. Het eigenlijke werk van het maken van de DOM voor balken, markeringen en teken gebeurt in de _setOption
methode. Dit lijkt misschien wat tegen-intuïtief om mee te beginnen, maar daar is een geldige reden voor.
_create: function () this.element.addClass ('bullet-chart'); // Chart-container this._container = $ ('') .appendTo (this.element); this._setOptions ('size': this.options.size, 'ticks': this.options.ticks, 'bars': this.options.bars, 'markers': this.options.markers);
Merk op dat de balken, markeringen en maatstreepjes ook kunnen worden gewijzigd door opties in te stellen op de widget. Als we de code bewaarden voor de constructie ervan _create
, we zouden ons van binnen herhalen _setOption
. Door de code naar te verplaatsen _setOption
en het aanroepen van _create
verwijdert de duplicatie en centraliseert ook de constructie.
Bovendien laat de bovenstaande code je een andere manier zien om opties in de widget in te stellen. Met de _setOptions
methode (let op het meervoud), je kunt meerdere opties in één keer instellen. Intern zal de fabriek individuele gesprekken voeren _setOption
voor elk van de opties.
_setOption
methodeVoor het opsommingsteken, de _setOption
methode is het werkpaard. Het behandelt het maken van de markeringen, balken en teken en ook alle wijzigingen die in deze eigenschappen zijn aangebracht. Het werkt door bestaande elementen te wissen en opnieuw te creëren op basis van de nieuwe waarde.
De _setOption
methode ontvangt zowel de optietoets als een waarde als argumenten. De sleutel is de naam van de optie, die moet overeenkomen met een van de sleutels in de standaardopties. Als u bijvoorbeeld de balken in de widget wilt wijzigen, voert u de volgende oproep uit:
$ ('# elem'). bulletchart ('option', 'bars', [title: 'New Marker', waarde: 50])
De _setOption
methode voor de bulletchart ziet er zo uit:
_setOption: function (key, value) var self = this, prev = this.options [key], fnMap = 'bars': function () createBars (value, self); , 'markers': function () createMarkers (value, self); , 'ticks': function () createTickBar (value, self); , 'size': function () self.element.find ('. chart-container') .css ('width', value + '%'); ; // base this._super (sleutel, waarde); if (key in fnMap) fnMap [key] (); // Brandgebeurtenis this._triggerOptionChanged (sleutel, vorige, waarde);
Hier maken we een eenvoudige hash van de optienaam aan de bijbehorende functie. Met deze hash werken we alleen aan geldige opties en negeren we ongeldige opties. Er gebeuren hier nog twee dingen: een oproep aan _super()
en het activeren van de optie veranderde gebeurtenis. We zullen ze later in dit artikel bekijken.
Voor elk van de opties die de DOM wijzigen, noemen we een specifieke hulpmethode. De hulpmethoden, createBars
, createMarkers
en createTickBar
worden opgegeven buiten de widgetinstance-eigenschappen. Dit komt omdat ze hetzelfde zijn voor alle widgets en niet afzonderlijk hoeven te worden gemaakt voor elke widgetinstantie.
// Creation functions function createTickBar (ticks, widget) // Wis bestaande widget._container.find ('. Tick-bar'). Remove (); var tickBar = $ (''); $ .each (ticks, function (idx, tick) var t = $ ('') .css (' links ', aanvinken +'% '); var tl = $ ('') .css (' left ', tick +'% ') .text (vinkje); tickBar.append (t); tickBar.append (tl); ); widget._container.append (tickBar); functie createMarkers (markeringen, widget) // bestaande widget verwijderen._container.find ('. marker'). remove (); $ .each (markers, functie (idx, m) var marker = $ ('') .css (left: m.value +'% ') .addClass (m.css) .attr (' marker-index ', idx); widget._container.append (marker); ); functie createBars (balken, widget) // Wis bestaande widget._container.find ('. bar'). remove (); $ .each (balken, functie (idx, balk) var bar = $ ('') .css (left: 0, width:' 0% ') .addClass (bar.css) .attr (' bar-index ', idx) .animation (width: bar.value +'% ' ); widget._container.append (bar); );
Alle creatie-functies werken op percentages. Dit zorgt ervoor dat de grafiek mooi terugloopt wanneer u het formaat van het element wijzigt.
Zonder opties die zijn opgegeven bij het maken van de widget, worden de standaardwaarden gebruikt. Dit is de rol van de opties
eigendom. Voor de bulletchart zien onze standaardopties er zo uit:
$ .widget ('nt.bulletchart', options: // percentage: 0 - 100 size: 100, // [title: 'Sample Bar', waarde: 75, css: "], bars: [] , // [title: 'Sample Marker', waarde: 50, css: "], markeringen: [], // ticks - percent values ticks: [0, 10, 20, 30, 40, 50, 60 , 70, 80, 90, 100], ...
We beginnen met een grootte van 100%, geen staven en markeringen en met tikken geplaatst elk 10%. Met deze standaardwaarden zou onze bullet-grafiek er als volgt uit moeten zien:
Tot nu toe hebben we gezien hoe je de widget kunt maken met _create
en het bijwerken met behulp van _setOption
. Er is een andere levenscyclusmethode die wordt aangeroepen wanneer je een widget vernietigt. Dit is de _vernietigen
methode. Wanneer je belt $ ( '# Elem'). Bulletchart ( 'vernietigen')
, de widgetfabriek belt intern _vernietigen
op uw widgetinstantie. De widget is verantwoordelijk voor het verwijderen van alles wat het in de DOM heeft geïntroduceerd. Dit kan klassen en andere DOM-elementen zijn die zijn toegevoegd in de _create
methode. Dit is ook een goede plek om eventhandlers te ontkoppelen. De _vernietigen
moet precies het tegenovergestelde zijn van de _create
methode.
Voor de bullet-grafiekwidget, de _vernietigen
is vrij eenvoudig:
_destroy: function () this.element.removeClass ('bullet-chart'); this.element.empty (); ,
Onze bulletchart-widget is bijna compleet, behalve één laatste functie: legende. De legende is vrij essentieel, omdat deze meer betekenis zal geven aan de markeringen en balken. In deze sectie zullen we een legenda toevoegen naast het diagram.
In plaats van deze functie rechtstreeks toe te voegen aan de bulletchart-widget, zullen we een subklasse maken, bulletchart2
, dat zal de legende ondersteunen. In dit proces zullen we ook enkele van de interessante kenmerken van Widget Factory inheritance bekijken.
De Widget Factory ondersteunt subklassen van een widget om meer gespecialiseerde versies te maken. Eerder in het artikel hebben we de API voor gezien $ .Widget ()
, die drie argumenten had:
jQuery.widget (naam [, basis], prototype)
Met de tweede parameter kunnen we een basisklasse kiezen voor onze widget. Onze bulletchart2
widget, welke subklasse bulletchart
, zal de volgende handtekening hebben:
$ .widget ('nt.bulletchart2', $ .nt.bulletchart, options: // Legenda van legendes tonen / verbergen: true, // dit zorgt ervoor dat we dezelfde naamruimte behouden als de basis-widgetEventPrefix: $ .nt.bulletchart .prototype.widgetEventPrefix, _create: function () ..., _destroy: function () ..., _setOption: function (key, value) ...)
Er zijn hier enkele interessante dingen om op te merken:
nt.bulletchart2
.$ .nt.bulletchart
. Ook als we een van de standaard jQuery UI-widgets zouden subclasseren, zouden we ernaar verwijzen $ .Ui.widget-naam
widgetEventPrefix
is een nieuwe eigenschap die we nog niet eerder hebben gezien. Daar komen we aan als we het hebben over gebeurtenissen. De rest van de instantie-eigenschappen moet bekend zijn.Omdat we meer DOM-elementen met de legenda toevoegen, moeten we de DIG-elementen overschrijven _create
methode. Dit betekent ook dat we moeten overschrijven _vernietigen
, om symmetrisch te zijn.
_create: function () var self = this; this._legend = $ ('') .appendTo (this.element); ... // Bel de base this._super (); this._setOption ('legend', this.options.legend); , _destroy: function () this.element.find ('. legend'). empty (); ... this._super (); ,
Hier zien we opnieuw hetzelfde patroon als eerder _create
methode. We maken de container voor de legenda en bellen vervolgens _setOption
om de rest van de legende te bouwen. Omdat we de _create
, we moeten ervoor zorgen dat we de basis noemen _create
. We doen dit met de oproep aan _super
. Evenzo, in _vernietigen
, we zien ook de oproep aan _super
.
Nu vraag je je misschien af: hoe weet de widget welke supermethode moet worden aangeroepen met een eenvoudige, niet-gekwalificeerde methode _super
aanroeping? De smarts daarvoor liggen in de ingewanden van de widget-fabriek. Wanneer een widget een subklasse heeft, stelt de fabriek de widget in _super
verwijzing anders voor elk van de instantie-functies. Dus als je belt _super
van uw voorbeeldmethode wijst het altijd naar het goede _super
methode.
Aangezien de bulletchart veranderende markeringen en staven ondersteunt, moet de legenda in overeenstemming zijn met die wijzigingen. Daarnaast ondersteunen we ook het wisselen van de zichtbaarheid van markeringen en staven door op de legendapunten te klikken. Dit wordt handig wanneer u meerdere markeringen en staven hebt. Door een paar elementen te verbergen, kun je de anderen duidelijker zien.
Om de synchronisatie van de legenda met de wijzigingen aan markeringen en balken te ondersteunen, de bulletchart2
widget moet luisteren naar alle wijzigingen die met die eigenschappen gebeuren. De basis bulletchart vuurt al een keer een wijzigingsgebeurtenis wanneer de opties veranderen. Hier is het bijbehorende fragment van de basiswidget:
_setOption: functie (sleutel, waarde) var self = this, prev = this.options [key]; ... // base this._super (sleutel, waarde); if (key in fnMap) fnMap [key] (); // Brandgebeurtenis this._triggerOptionChanged (sleutel, vorige, waarde); , _triggerOptionChanged: function (optionKey, previousValue, currentValue) this._trigger ('setOption', type: 'setOption', option: optionKey, previous: previousValue, current: currentValue);
Wanneer een optie is ingesteld, is de SetOption
evenement is ontslagen. De gebeurtenisgegevens bevatten de vorige en nieuwe waarde voor de optie die is gewijzigd.
Door naar deze gebeurtenis in de widget met subklassen te luisteren, weet u wanneer de markeringen of balken veranderen. De bulletchart2
widget abonneert zich op dit evenement in zijn _create
methode. Abonneren op widgets-evenementen wordt bereikt met de aanroep naar this.element.on ()
. this.element
verwijst naar het jQuery-element waarop de widget is geïnstantieerd. Aangezien het evenement op het element wordt geactiveerd, moet ons evenementabonnement daarop plaatsvinden.
_create: function () var self = this; this._legend = $ ('') .appendTo (this.element); ... // Legenda toepassen op wijzigingen in markeringen en balken this.element.on (' bulletchart: setoption ', functie (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); ); // Bel de basis this._super (); this._setOption ('legend', this.options.legend);
Let op de naam van het evenement gebruikt voor het abonneren: 'Bulletchart: SetOption'
. Als beleid voegt de widgetfabriek een voorvoegsel voor gebeurtenissen toe die worden afgevuurd vanuit de widget. Standaard is dit voorvoegsel de naam van de widget, maar dit kan eenvoudig worden gewijzigd met de widgetEventPrefix
eigendom. De basis bulletchart-widget verandert dit in 'Bulletchart:'
.
$ .widget ('nt.bulletchart', options: ..., widgetEventPrefix: 'bulletchart:' ...);
We moeten ons ook abonneren op 'Klik'
gebeurtenissen op de legendapunten om de bijbehorende markering / bar te verbergen / tonen. We doen dit met de _op
methode. Deze methode neemt een hash van de gebeurtenissignatuur op in de handlerfunctie. De context van de handler (deze
) is correct ingesteld op de widgetinstantie. Een ander gemak met _op
is dat de widget-fabriek automatisch de gebeurtenissen bij vernietiging losmaakt.
_create: function () ... // Luister naar klikken op de legend-items this._on ('click .legend-item': function (event) var elt = $ (event.currentTarget), item = elt.data ('kaartitem'), selector = '[' + item.type + '-index =' + item.index + ']'; this.element.find (selector). fadeToggle (); elt.toggleClass (' fade ');); ...
De Widget-fabriek pakt nog een aantal andere dingen op waarvan je op de hoogte moet zijn.
Tot nu toe hebben we slechts één manier gezien om methoden aan te roepen voor de widget. We deden dit met $ ( '# Elem) .bulletchart (' methode-naam ')
. Dit laat echter alleen toe openbare methoden te gebruiken zoals 'option', 'destroy', 'on', 'off'. Als u die methoden rechtstreeks op de widgetinstantie wilt aanroepen, is er een manier om dat te doen. De widgetfabriek koppelt de widgetinstantie aan de gegevens()
object van het element. Je kunt deze instantie als volgt krijgen:
var widget = $ ('# elem'). data ('bulletchart'); widget.destroy ();
Als u bovendien alle bulletchart-widgets op de pagina in handen wilt krijgen, is er ook een selector voor:
var allCharts = $ (': nt-bulletchart');
Er zijn een paar speciale methoden waarvan u op de hoogte moet zijn, die minder vaak worden gebruikt: _getCreateEventData ()
en _getCreateOptions ()
. De eerste wordt gebruikt om gebeurtenisgegevens aan te koppelen voor de gebeurtenis 'create' die wordt geactiveerd nadat de oproep is voltooid _create
.
_getCreateOptions
is voor het toevoegen van extra standaardopties voor de widget of het vervangen van bestaande opties. De door de gebruiker verstrekte opties hebben voorrang op opties die door deze methode worden geretourneerd, die op zijn beurt de standaard widgetopties overschrijven.
Het zit er op! Als u verder wilt verkennen, zijn de onderstaande referenties goed voor u. De bron van informatie is natuurlijk altijd de broncode. Ik raad aan om de jquery.ui.widget-bron te lezen op GitHub.