Comment jQuery UI utilise la bibliothèque de widgets


Nous allons créer une barre de progression. Comme le montre l'exemple ci-dessous, cela peut être fait en appelant jQuery.widget() avec deux paramètres : le nom du plugin à créer et un littéral d'objet contenant les fonctions qui prennent en charge le plugin. Lorsque le plugin est appelé, il créera une nouvelle instance de plugin et toutes les fonctions seront exécutées dans le contexte de cette instance. Cela diffère du plugin jQuery standard de deux manières importantes. Premièrement, le contexte est un objet, pas un élément DOM. Deuxièmement, le contexte est toujours un objet unique, pas une collection.

$.widget( "custom.progressbar", {
    _create: function() {
        var progress = this.options.value + "%";
        this.element
            .addClass( "progressbar" )
            .text( progress );
    }
});

Le nom du plugin doit inclure l'espace de noms. Dans cet exemple, nous avons utilisé l'espace de noms custom. Vous ne pouvez créer des espaces de noms qu'à un niveau de profondeur, donc custom.progressbar est un nom de plugin valide et very.custom.progressbar n'est pas un nom de plugin valide.

On voit que la Widget Factory nous propose deux propriétés. this.element est un objet jQuery contenant un élément. Si notre plugin est appelé sur un objet jQuery contenant plusieurs éléments, une instance de plugin distincte sera créée pour chaque élément, et chaque instance aura son propre this.element. Le deuxième attribut, this.options, est un hachage de paires clé/valeur contenant toutes les options du plugin. Ces options peuvent être transmises au plugin comme suit :

$( "<div></div>" )
    .appendTo( "body" )
    .progressbar({ value: 20 });

Quand on appelle jQuery.widget(), il étend jQuery en ajoutant des fonctions à jQuery.fn (le système utilisé pour créer des plugins standards). Le nom de la fonction ajouté est basé sur le nom que vous avez transmis à jQuery.widget() sans l'espace de noms - "progressbar". Les options transmises au plugin obtiennent les valeurs définies dans l'instance du plugin. Comme le montre l'exemple ci-dessous, nous pouvons spécifier une valeur par défaut pour n'importe laquelle des options. Lors de la conception de votre API, vous devez être conscient des cas d'utilisation les plus courants de votre plugin afin de pouvoir définir les valeurs par défaut appropriées et être sûr de rendre toutes les options vraiment facultatives.

$.widget( "custom.progressbar", {
 
    // Default options.
    options: {
        value: 0
    },
    _create: function() {
        var progress = this.options.value + "%";
        this.element
            .addClass( "progressbar" )
            .text( progress );
    }
});

Appel des méthodes du plugin

Maintenant nous pouvons initialiser notre barre de progression, nous allons effectuer des actions en appelant des méthodes sur l'instance du plugin. Pour définir une méthode de plugin, nous référençons simplement la fonction dans l'objet auquel nous passons jQuery.widget(). Nous pouvons également définir des méthodes « privées » en préfixant le nom de la fonction par un trait de soulignement.

$.widget( "custom.progressbar", {
 
    options: {
        value: 0
    },
 
    _create: function() {
        var progress = this.options.value + "%";
        this.element
            .addClass( "progressbar" )
            .text( progress );
    },
 
    // Create a public method.
    value: function( value ) {
 
        // No value passed, act as a getter.
        if ( value === undefined ) {
            return this.options.value;
        }
 
        // Value passed, act as a setter.
        this.options.value = this._constrain( value );
        var progress = this.options.value + "%";
        this.element.text( progress );
    },
 
    // Create a private method.
    _constrain: function( value ) {
        if ( value > 100 ) {
            value = 100;
        }
        if ( value < 0 ) {
            value = 0;
        }
        return value;
    }
});

Afin d'appeler une méthode sur une instance de plugin, vous transmettez le nom de la méthode au plugin jQuery. Si la méthode que vous appelez accepte des paramètres, vous transmettez simplement ces paramètres après le nom de la méthode.

Remarque : Exécutez la méthode en passant le nom de la méthode à la même fonction jQuery utilisée pour initialiser le plugin. Ceci est fait pour éviter la pollution de l'espace de noms jQuery tout en conservant les appels de méthode enchaînés. Plus loin dans ce chapitre, nous verrons d’autres utilisations qui semblent plus naturelles.

La méthode
var bar = $( "<div></div>" )
    .appendTo( "body" )
    .progressbar({ value: 20 });
 
// Get the current value.
alert( bar.progressbar( "value" ) );
 
// Update the value.
bar.progressbar( "value", 50 );
 
// Get the current value again.
alert( bar.progressbar( "value" ) );

Utiliser l'option

option() est automatiquement fournie aux plugins. La méthode option() vous permet d'obtenir et de définir des options après l'initialisation. Cette méthode est similaire aux méthodes .css() et .attr() de jQuery : vous pouvez transmettre simplement un nom à utiliser comme évaluateur, vous pouvez transmettre un nom et une valeur à utiliser comme paramètre, ou vous pouvez transmettre une paire nom de clé/valeur de clé. . pour définir plusieurs valeurs. Lorsqu'il est utilisé comme évaluateur, le plugin renverra la valeur actuelle de l'option correspondant au nom transmis. Lorsqu'elle est utilisée comme setter, la méthode _setOption du plugin sera appelée pour chaque option définie. Nous pouvons spécifier une méthode _setOption dans notre plugin pour réagir aux changements d'options. Pour que les actions qui modifient les options soient effectuées indépendamment, nous pouvons surcharger _setOptions.

$.widget( "custom.progressbar", {
    options: {
        value: 0
    },
    _create: function() {
        this.options.value = this._constrain(this.options.value);
        this.element.addClass( "progressbar" );
        this.refresh();
    },
    _setOption: function( key, value ) {
        if ( key === "value" ) {
            value = this._constrain( value );
        }
        this._super( key, value );
    },
    _setOptions: function( options ) {
        this._super( options );
        this.refresh();
    },
    refresh: function() {
        var progress = this.options.value + "%";
        this.element.text( progress );
    },
    _constrain: function( value ) {
        if ( value > 100 ) {
            value = 100;
        }
        if ( value < 0 ) {
            value = 0;
        }
        return value;
    }
});

Ajouter des rappels

Le moyen le plus simple d'étendre un plugin est d'ajouter des rappels afin que les utilisateurs puissent réagir lorsque l'état du plugin change. Nous pouvons voir l'exemple suivant sur la façon d'ajouter un rappel à la barre de progression lorsque la progression atteint 100 %. La méthode _trigger() prend trois paramètres : le nom du rappel, un objet événement jQuery qui démarre le rappel et un hachage des données associées à l'événement. Le nom de rappel est le seul paramètre obligatoire, mais les autres paramètres sont utiles pour les utilisateurs qui souhaitent implémenter des fonctionnalités personnalisées sur le plugin. Par exemple, si nous créons un plugin déplaçable, nous pouvons transmettre l'événement mousemove lorsque le rappel de glisser est déclenché, ce qui permettra à l'utilisateur de réagir au glissement en fonction des coordonnées x/y fournies par l'objet événement. Notez que l'événement d'origine transmis à _trigger() doit être un événement jQuery, et non un événement de navigateur natif.

$.widget( "custom.progressbar", {
    options: {
        value: 0
    },
    _create: function() {
        this.options.value = this._constrain(this.options.value);
        this.element.addClass( "progressbar" );
        this.refresh();
    },
    _setOption: function( key, value ) {
        if ( key === "value" ) {
            value = this._constrain( value );
        }
        this._super( key, value );
    },
    _setOptions: function( options ) {
        this._super( options );
        this.refresh();
    },
    refresh: function() {
        var progress = this.options.value + "%";
        this.element.text( progress );
        if ( this.options.value == 100 ) {
            this._trigger( "complete", null, { value: 100 } );
        }
    },
    _constrain: function( value ) {
        if ( value > 100 ) {
            value = 100;
        }
        if ( value < 0 ) {
            value = 0;
        }
        return value;
    }
});

Les fonctions de rappel ne sont essentiellement que des options supplémentaires, vous pouvez donc les obtenir et les définir comme les autres options. Chaque fois qu'un rappel est exécuté, un événement correspondant sera déclenché. Le type d'événement est déterminé par le nom du plug-in de connexion et le nom de la fonction de rappel. Les rappels et les événements acceptent les deux mêmes paramètres : un objet événement et un hachage de données associé à l'événement, comme indiqué dans l'exemple ci-dessous. Votre plugin devra peut-être inclure des fonctionnalités qui empêchent les utilisateurs de l'utiliser, et la meilleure façon de le faire est de créer un rappel révocable. Les utilisateurs peuvent annuler les rappels ou les événements associés, tout comme ils peuvent annuler n'importe quel événement natif, en appelant event.preventDefault() ou en retournant false. Si l'utilisateur révoque le rappel, la méthode _trigger() renverra false afin que vous puissiez implémenter la fonctionnalité appropriée dans le plugin.

var bar = $( "<div></div>" )
    .appendTo( "body" )
    .progressbar({
        complete: function( event, data ) {
            alert( "Callbacks are great!" );
        }
    })
    .bind( "progressbarcomplete", function( event, data ) {
        alert( "Events bubble and support many handlers for extreme flexibility." );
        alert( "The progress bar value is " + data.value );
    });
 
bar.progressbar( "option", "value", 100 );

Essence

Maintenant que nous avons vu comment créer un plugin à l'aide de Widget Factory, voyons comment cela fonctionne réellement. Lorsque vous appelez jQuery.widget(), cela créera un constructeur pour le plugin et définira l'objet que vous avez transmis comme prototype pour l'instance du plugin. Toutes les fonctionnalités automatiquement ajoutées au plugin proviennent d'un prototype de widget de base, défini comme jQuery.Widget.prototype. Lorsqu'une instance de plugin est créée, elle est stockée sur l'élément DOM d'origine en utilisant jQuery.data avec le nom du plugin comme clé.

Étant donné que l'instance du plugin est liée directement à l'élément DOM, vous pouvez accéder directement à l'instance du plugin sans passer par les méthodes du plugin. Cela vous permettra d'appeler des méthodes directement sur l'instance du plugin sans passer le nom de la méthode sous forme de chaîne, et vous aurez également un accès direct aux propriétés du plugin.

var bar = $( "<div></div>" )
    .appendTo( "body" )
    .progressbar()
    .data( "progressbar" );
 
// Call a method directly on the plugin instance.
bar.option( "value", 50 );
 
// Access properties on the plugin instance.
alert( bar.options.value );

Vous pouvez également créer une instance sans parcourir les méthodes du plugin et simplement appeler le constructeur directement avec des options et des éléments :

var bar = $.custom.progressbar( {}, $( "<div></div>" ).appendTo( "body") );
 
// Same result as before.
alert( bar.options.value );

Étendre le prototype du plugin

Le plus gros avantage de Les plug-ins ayant des constructeurs et des prototypes sont faciles à étendre. En ajoutant ou en modifiant des méthodes sur le prototype du plugin, nous pouvons modifier le comportement de toutes les instances du plugin. Par exemple, si nous voulions ajouter une méthode à la barre de progression qui réinitialise la progression à 0%, nous pourrions ajouter cette méthode au prototype et elle serait appelable sur toutes les instances du plugin.

$.custom.progressbar.prototype.reset = function() {
    this._setOption( "value", 0 );
};

Pour plus de détails sur l'extension des widgets et comment créer un tout nouveau widget au-dessus d'un widget existant, consultez via le Widget Factory ) widget d'extension (Widget) .

Nettoyage

Autoriser les utilisateurs à appliquer des plugins, puis à les désappliquer dans certaines situations. Vous pouvez le faire via la méthode _destroy(). Dans la méthode _destroy(), vous devez annuler toutes les actions effectuées par le plugin lors de l'initialisation et de son utilisation ultérieure. _destroy() est appelé via la méthode .destroy(), qui est automatiquement appelée lorsque l'élément lié à l'instance du plugin est supprimé du DOM, cela peut donc être utilisé pour le garbage collection. La méthode de base .destroy() gère également certaines opérations de nettoyage courantes, telles que la suppression des références d'instance de l'élément DOM du widget, la dissociation de tous les événements de l'espace de noms du widget de l'élément et la dissociation de tous les événements ajoutés à l'aide des événements .destroy(). _bind()

$.widget( "custom.progressbar", {
    options: {
        value: 0
    },
    _create: function() {
        this.options.value = this._constrain(this.options.value);
        this.element.addClass( "progressbar" );
        this.refresh();
    },
    _setOption: function( key, value ) {
        if ( key === "value" ) {
            value = this._constrain( value );
        }
        this._super( key, value );
    },
    _setOptions: function( options ) {
        this._super( options );
        this.refresh();
    },
    refresh: function() {
        var progress = this.options.value + "%";
        this.element.text( progress );
        if ( this.options.value == 100 ) {
            this._trigger( "complete", null, { value: 100 } );
        }
    },
    _constrain: function( value ) {
        if ( value > 100 ) {
            value = 100;
        }
        if ( value < 0 ) {
            value = 0;
        }
        return value;
    },
    _destroy: function() {
        this.element
            .removeClass( "progressbar" )
            .text( "" );
    }
});

Fermer le commentaire

Widget Factory n'est qu'un moyen de créer des plug-ins avec état. Il existe quelques autres modèles différents, chacun avec ses propres forces et faiblesses. La fabrique de widgets résout de nombreux problèmes courants et améliore considérablement l'efficacité. Elle améliore également considérablement la réutilisation du code, ce qui la rend adaptée à l'interface utilisateur jQuery et à d'autres plug-ins avec état.

Veuillez noter que dans cette section, nous utilisons l'espace de noms custom. L'espace de noms ui est réservé par le plugin officiel jQuery UI. Lors de la création de votre propre plugin, vous devez créer votre propre espace de noms. Cela permettra de mieux comprendre d'où vient le plug-in et à quelle portée il appartient.