Pendant longtemps, le seul moyen d'écrire des contrôles personnalisés dans jQuery était d'étendre la $ .fn
espace de noms. Cela fonctionne bien pour les widgets simples, cependant, au fur et à mesure que vous construisez des widgets avec état, cela devient rapidement encombrant. Pour vous aider dans le processus de création de widgets, l'équipe de l'interface utilisateur de jQuery a introduit Widget Factory, qui supprime la plupart des règles habituelles associées à la gestion d'un widget..
La fabrique de widgets, une partie de la jQuery UI Core, fournit un moyen orienté objet de gérer le cycle de vie d'un widget. Ces activités du cycle de vie comprennent:
Explorons cette API en construisant un simple widget graphique à puces.
Avant de construire ce widget, nous allons comprendre quelques éléments constitutifs du widget. Le graphique à puces est un concept introduit par Stephen Few en tant que variation du graphique à barres..
Le graphique consiste en un ensemble de barres et de marqueurs superposés pour indiquer les performances relatives. Il y a une échelle quantitative pour montrer la plage de valeurs actuelle. En empilant les barres et les marqueurs de cette manière, davantage d'informations peuvent être transmises sans compromettre la lisibilité. La légende raconte le genre d'informations que nous traçons.
Le code HTML de ce graphique ressemble à ceci:
Ligne verte0255075100
Notre widget, que nous appellerons jquery.bulletchart
, générera dynamiquement ce code HTML à partir des données fournies. Le widget final peut être visualisé dans les fichiers sources, que vous pouvez télécharger à partir de GitHub. L'appel à créer le widget devrait ressembler à ceci:
$ ('. chart'). bulletchart (taille: 86, barres: [titre: 'Cible projetée', valeur: 75, css: ", titre: 'Cible réelle', valeur: 50, css: ' blue '], marqueurs: [titre:' ligne verte ', valeur: 80, css:' vert ', titre:' seuil minimal ', valeur: 50, css:' rouge '], ticks: [ 0, 25, 50, 75, 100]);
Toutes les valeurs sont en pourcentages. le Taille
Cette option peut être utilisée lorsque vous souhaitez avoir plusieurs diagrammes à puces placés côte à côte avec une taille relative. le tiques
Cette option est utilisée pour mettre les étiquettes sur la balance. Les marqueurs et les barres sont spécifiés comme un tableau de littéraux d’objet avec Titre
, valeur
et css
Propriétés.
Maintenant que nous connaissons la structure du widget, commençons par le construire. Un widget est créé en appelant $ .widget ()
avec le nom du widget et un objet contenant ses méthodes d'instance. L'API exacte ressemble à:
jQuery.widget (nom [, base], prototype)
Pour l'instant, nous allons travailler uniquement avec les arguments nom et prototype. Pour le diagramme à puces, notre module de remplacement de base ressemble à ceci:
$ .widget ('nt.bulletchart', options: , _create: function () , _destroy: function () , _setOption: function (clé, valeur) );
Il est recommandé de toujours placer les noms de vos widgets en espace de nom. Dans ce cas, nous utilisons 'nt.bulletchart'. Tous les widgets jQuery UI se trouvent sous le 'ui'espace de noms. Bien que nous modifions le widget, l'appel à la création d'un widget sur un élément n'inclut pas l'espace de nom. Ainsi, pour créer un graphique à puces, nous appellerions simplement $ ('# elem'). bulletchart ()
.
Les propriétés de l'instance sont spécifiées après le nom du widget. Par convention, toutes les méthodes privées du widget doivent porter le préfixe '_'. Certaines propriétés spéciales sont attendues par la fabrique de widgets. Ceux-ci incluent le options
, _créer
, _détruire
et _setOption
.
options
: Ce sont les options par défaut pour le widget_créer
: La fabrique de widgets appelle cette méthode lors de la première instanciation du widget. Ceci est utilisé pour créer le DOM initial et attacher tout gestionnaire d'événement._init
: Suite à l'appel de _créer
, les appels d'usine _init
. Ceci est généralement utilisé pour réinitialiser le widget à son état initial. Une fois le widget créé, appelez le constructeur du widget simple, par exemple: $ .bulletchart (), va également réinitialiser le widget. Cet appel interne _init
._setOption
: Appelé lorsque vous définissez une option sur le widget, avec un appel tel que: $ ('# elem'). bulletchart ('option', 'taille', 100)
. Nous verrons plus tard d'autres moyens de définir des options sur le widget.._créer
Notre widget bulletchart prend vie dans le _créer
méthode. Voici où nous construisons la structure de base pour le graphique. le _créer
fonction peut être vu ci-dessous. Vous remarquerez qu'il ne se passe pas grand chose ici à part la création du conteneur de niveau supérieur. Le travail réel de création du DOM pour les barres, les marqueurs et les ticks a lieu dans le _setOption
méthode. Cela peut sembler quelque peu contre-intuitif au départ, mais il y a une raison valable à cela..
_create: function () this.element.addClass ('bullet-chart'); // conteneur de graphique this._container = $ ('') .appendTo (this.element); this._setOptions ('taille': this.options.size, 'ticks': this.options.ticks, 'barres': this.options.bars, 'marqueurs': this.options.markers);
Notez que les barres, les marqueurs et les graduations peuvent également être modifiés en définissant des options sur le widget. Si nous avons gardé le code pour sa construction à l'intérieur _créer
, nous nous répéterions à l'intérieur _setOption
. En déplaçant le code vers _setOption
et l'invoquant de _créer
supprime la duplication et centralise également la construction.
De plus, le code ci-dessus vous montre un autre moyen de définir des options sur le widget. Avec le _setOptions
méthode (notez le pluriel), vous pouvez définir plusieurs options en une fois. En interne, l’usine fera des appels individuels sur _setOption
pour chacune des options.
_setOption
méthodePour le graphique à puces, le _setOption
méthode est le bourreau de travail. Il gère la création des marqueurs, des barres et des ticks ainsi que toutes les modifications apportées à ces propriétés. Cela fonctionne en effaçant tous les éléments existants et en les recréant en fonction de la nouvelle valeur.
le _setOption
La méthode reçoit à la fois la clé d’option et une valeur sous forme d’arguments. La clé est le nom de l'option, qui devrait correspondre à l'une des clés des options par défaut. Par exemple, pour changer les barres du widget, appelez l’appel suivant:
$ ('# elem'). bulletchart ('option', 'bars', [titre: 'Nouveau marqueur', valeur: 50])
le _setOption
méthode pour le diagramme à puces ressemble à ceci:
_setOption: function (clé, valeur) var self = this, prev = this.options [clé], fnMap = 'bars': function () createBars (value, self); , 'marqueurs': function () createMarkers (value, self); , 'ticks': function () createTickBar (value, self); , 'size': function () self.element.find ('. chart-container') .css ('width', value + '%'); ; // base this._super (clé, valeur); if (clé dans fnMap) fnMap [clé] (); // événement Fire this._triggerOptionChanged (clé, prev, valeur);
Ici, nous créons un hachage simple de l’option-name à la fonction correspondante. En utilisant ce hachage, nous ne travaillons que sur des options valides et ignorons en silence celles qui ne sont pas valides. Deux autres choses se passent ici: un appel à _super()
et déclencher l'événement d'option modifiée. Nous les examinerons plus tard dans cet article.
Pour chacune des options modifiant le DOM, nous appelons une méthode d'assistance spécifique. Les méthodes d'assistance, createBars
, createMarkers
et createTickBar
sont spécifiés en dehors des propriétés d'instance de widget. En effet, ils sont identiques pour tous les widgets et n'ont pas besoin d'être créés individuellement pour chaque instance de widget..
// Fonctions de création function createTickBar (ticks, widget) // Efface le widget existant._container.find ('. Tick-bar'). Remove (); var tickBar = $ (''); $ .each (ticks, fonction (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 (marqueurs, widget) // Efface le widget existant._container.find ('. marqueur'). remove (); $ .each (marqueurs, fonction (idx, m) var marqueur = $ ('') .css (left: m.value +'% ') .addClass (m.css) .attr (' marqueur-index ', idx); widget._container.append (marqueur); ); function createBars (barres, widget) // Efface le widget existant._container.find ('. bar'). remove (); $ .each (barres, fonction (idx, bar) var bar = $ ('') .css (left: 0, width:' 0% ') .addClass (bar.css) .attr (' bar-index ', idx) .animate (width: bar.value +'% ' ) widget._container.append (barre); );
Toutes les fonctions de création fonctionnent sur des pourcentages. Cela garantit que le graphique se rétablit bien lorsque vous redimensionnez l'élément contenant.
Sans aucune option spécifiée lors de la création du widget, les valeurs par défaut entrent en jeu. C’est le rôle du options
propriété. Pour le diagramme à puces, nos options par défaut ressemblent à ceci:
$ .widget ('nt.bulletchart', options: // pourcentage: 0 - 100 taille: 100, // [titre: 'Sample Bar', valeur: 75, css: "], barres: [] , // [titre: 'Sample Marker', valeur: 50, css: "], marqueurs: [], // ticks - valeurs en pourcentage ticks: [0, 10, 20, 30, 40, 50, 60 , 70, 80, 90, 100],…
Nous commençons avec une taille de 100%, pas de barres et de marqueurs et avec des tiques placés tous les dix%. Avec ces valeurs par défaut, notre tableau à puces devrait ressembler à ceci:
Jusqu'à présent, nous avons vu comment créer le widget en utilisant _créer
et le mettre à jour en utilisant _setOption
. Il existe une autre méthode de cycle de vie, qui sera appelée lorsque vous détruisez un widget. C'est le _détruire
méthode. Quand vous appelez $ ('# elem'). bulletchart ('destroy')
, la fabrique de widgets appelle en interne _détruire
sur votre instance de widget. Le widget est responsable de la suppression de tout ce qu'il a introduit dans le DOM. Cela peut inclure des classes et d’autres éléments DOM ajoutés dans la _créer
méthode. C'est également un bon endroit pour dissocier tous les gestionnaires d'événements. le _détruire
devrait être l'exact opposé de la _créer
méthode.
Pour le widget graphique à puces, le _détruire
est assez simple:
_destroy: function () this.element.removeClass ('bullet-chart'); this.element.empty (); ,
Notre widget bulletchart est presque terminé, à l'exception d'une dernière fonctionnalité: Légende. La légende est essentielle car elle donnera plus de sens aux marqueurs et aux barres. Dans cette section, nous ajouterons une légende à côté du graphique..
Plutôt que d’ajouter cette fonctionnalité directement au widget bulletchart, nous allons créer une sous-classe., bulletchart2
, qui aura le support de la légende. Au cours de ce processus, nous examinerons également certaines des caractéristiques intéressantes de l'héritage de Widget Factory..
Widget Factory prend en charge le sous-classement d'un widget pour créer des versions plus spécialisées. Plus tôt dans l'article, nous avons vu l'API pour $ .widget ()
, qui avait trois arguments:
jQuery.widget (nom [, base], prototype)
Le deuxième paramètre nous permet de choisir une classe de base pour notre widget. Notre bulletchart2
widget, quelles sous-classes bulletchart
, aura la signature suivante:
$ .widget ('nt.bulletchart2', $ .nt.bulletchart, options: // Afficher / masquer la légende: true, // cela garantit que nous conservons le même espace de nom que la base widgetEventPrefix: $ .nt.bulletchart .prototype.widgetEventPrefix, _create: function () …, _destroy: function () …, _setOption: function (clé, valeur) …)
Il y a peu de choses intéressantes à noter ici:
nt.bulletchart2
.$ .nt.bulletchart
. De même, si nous devions sous-classer l’un des widgets standard de jQuery UI, nous les référencerions avec $ .ui.widget-name
widgetEventPrefix
est une nouvelle propriété que nous n’avons jamais vue auparavant. Nous y arriverons lorsque nous parlerons d’événements. Le reste des propriétés d'instance doit être familier.Puisque nous ajoutons plus d’éléments DOM avec la légende, nous devrons remplacer le _créer
méthode. Cela signifie également que nous devons remplacer _détruire
, afin d'être symétrique.
_create: function () var self = this; this._legend = $ ('') .appendTo (this.element);… // Appelez la base this._super (); this._setOption ('légende', this.options.legend); , _destroy: function () this.element.find ('. légende'). empty ();… this._super (); ,
Ici encore, nous voyons le même schéma que notre précédent _créer
méthode. Nous créons le conteneur pour la légende puis appelons _setOption
pour construire le reste de la légende. Puisque nous sommes en train de passer outre à la _créer
, nous devons nous assurer que nous appelons la base _créer
. Nous faisons cela avec l'appel à _super
. De même, dans _détruire
, nous voyons aussi l'appel à _super
.
Maintenant, vous vous demandez peut-être: comment le widget sait-il quelle super-méthode appeler avec une simple requête non qualifiée? _super
invocation? L'intelligence pour cela réside dans les entrailles de la fabrique de widgets. Quand un widget est sous-classé, l’usine configure le _super
référence différemment pour chacune des fonctions d'instance. Ainsi, lorsque vous appelez _super
de votre méthode d'instance, il pointe toujours vers le bon _super
méthode.
Comme le diagramme à puces prend en charge la modification des marqueurs et des barres, la légende doit être synchronisée avec ces modifications. De plus, nous soutiendrons également le basculement de la visibilité des marqueurs et des barres en cliquant sur les éléments de la légende. Cela devient utile lorsque vous avez plusieurs marqueurs et barres. En cachant quelques éléments, vous pouvez voir les autres plus clairement.
Pour prendre en charge la synchronisation de la légende avec les modifications apportées aux marqueurs et aux barres, la bulletchart2
Le widget doit être attentif aux modifications apportées à ces propriétés. Le diagramme à puces de base déclenche déjà un événement de modification chaque fois que ses options changent. Voici l'extrait correspondant du widget de base:
_setOption: function (clé, valeur) var self = this, prev = this.options [clé];… // base this._super (clé, valeur); if (clé dans fnMap) fnMap [clé] (); // événement Fire this._triggerOptionChanged (clé, prev, valeur); ►
Chaque fois qu'une option est définie, le setOption
l'événement est déclenché. Les données d'événement contiennent les valeurs précédente et nouvelle de l'option modifiée..
En écoutant cet événement dans le widget sous-classé, vous pouvez savoir quand les marqueurs ou les barres changent. le bulletchart2
widget s'abonne à cet événement dans son _créer
méthode. L’abonnement aux événements de widgets est réalisé avec l’appel à this.element.on ()
. this.element
pointe sur l'élément jQuery sur lequel le widget a été instancié. Comme l’événement sera déclenché sur l’élément, notre abonnement doit se dérouler sur cet élément..
_create: function () var self = this; this._legend = $ ('') .appendTo (this.element);… // Appliquer une légende aux modifications apportées aux marqueurs et aux barres this.element.on (' bulletchart: setoption ', fonction (événement, données) if (data.option ===') marqueurs ') createLegend (data.current, self.options.bars, self); else if (data.option ===' barres ') createLegend (self.options.markers, data.current, self); ) // Appelle la base this._super (); this._setOption ('légende', this.options.legend);
Notez le nom de l'événement utilisé pour s'abonner: 'bulletchart: setoption'
. En tant que stratégie, la fabrique de widgets attache un préfixe d'événement aux événements déclenchés à partir du widget. Par défaut, ce préfixe est le nom du widget, mais cela peut être facilement modifié avec le widgetEventPrefix
propriété. Le widget bulletchart de base change ceci en 'bulletchart:'
.
$ .widget ('nt.bulletchart', options: …, widgetEventPrefix: 'bulletchart:'…);
Nous devons également souscrire à 'Cliquez sur'
événements sur les éléments de légende pour masquer / afficher le marqueur / la barre correspondante. Nous faisons cela avec le _sur
méthode. Cette méthode utilise un hachage de la signature d'événement pour la fonction de gestionnaire. Le contexte du gestionnaire (ce
) est correctement défini sur l'instance du widget. Une autre commodité avec _sur
est que la fabrique de widgets annule automatiquement les événements sur destroy.
_create: function () … // Écoutez les clics sur les éléments de légende this._on ('cliquez sur .legend-item': function (événement) var elt = $ (event.currentTarget), item = elt.data ('chart-item'), selector = '[' + item.type + '-index =' + item.index + ']'; this.element.find (selector) .fadeToggle (); elt.toggleClass (' fade '););…
La fabrique de widgets contient quelques autres subtilités que vous devriez connaître..
Jusqu'à présent, nous n'avons vu qu'une seule façon d'appeler des méthodes sur le widget. Nous avons fait cela avec $ ('# elem) .bulletchart (' nom de la méthode ')
. Cependant, cela n'autorise que l'appel de méthodes publiques telles que 'option', 'destroy', 'on', 'off'. Si vous souhaitez invoquer ces méthodes directement sur l'instance de widget, vous pouvez le faire. La fabrique de widgets associe l’instance de widget à la Les données()
objet de l'élément. Vous pouvez obtenir cette instance comme suit:
var widget = $ ('# elem'). data ('bulletchart'); widget.destroy ();
De plus, si vous souhaitez mettre la main sur tous les widgets de graphiques à puces de la page, il existe également un sélecteur pour cela:
var allCharts = $ (': nt-bulletchart');
Il y a quelques méthodes spéciales que vous devriez connaître, qui sont utilisées moins fréquemment: _getCreateEventData ()
et _getCreateOptions ()
. Le premier est utilisé pour attacher des données d’événement pour l’événement 'create' qui est déclenché à la fin de l’appel à _créer
.
_getCreateOptions
sert à attacher des options par défaut supplémentaires pour le widget ou à remplacer celles existantes. Les options fournies par l'utilisateur remplacent les options renvoyées par cette méthode, qui à leur tour remplacent les options du widget par défaut..
C'est un wrap! Si vous souhaitez approfondir vos connaissances, les références ci-dessous devraient vous être très utiles. Bien entendu, la meilleure source d’information sera toujours le code source lui-même. Je vous encourage à lire la source jquery.ui.widget sur GitHub..