195 votes

Comment créer un plugin jQuery avec des méthodes?

Je suis en train d'écrire un plugin jQuery qui offrira de nouvelles fonctions/méthodes de l'objet qui l'appelle. Tous les tutoriels que j'lire en ligne (ont été de navigation pour les 2 dernières heures) comprennent, en plus, comment faire pour ajouter des options, mais pas de fonctions supplémentaires.

Voici ce que je cherche à faire:

//format div être un message contenant en appelant le plugin pour que la div

$("#mydiv").messagePlugin();
$("#mydiv").messagePlugin().saySomething("hello");

ou quelque chose le long de ces lignes. Voici à quoi ça se résume à: je l'appelle le plugin, puis-je appeler une fonction associée à ce plugin. Je n'arrive pas à trouver un moyen de le faire, et j'ai vu beaucoup de plugins de le faire avant.

Voici ce que j'ai jusqu'à présent pour le plugin:

jQuery.fn.messagePlugin = function() {
  return this.each(function(){
    alert(this);
  });

  //i tried to do this, but it does not seem to work
  jQuery.fn.messagePlugin.saySomething = function(message){
    $(this).html(message);
  }
};

Comment puis-je obtenir quelque chose comme ça?

Merci!!!!


Mise à jour le 18 Novembre, 2013: j'ai changé la réponse correcte à celui de Hari à la suite des commentaires et des upvotes.

317voto

Hari Karam Singh Points 1942

Selon le jQuery Plugin de Création de page (http://docs.jquery.com/Plugins/Authoring) de son mieux pour ne pas compliquer l'jQuery et jQuery.fn espaces de noms. Ils suggèrent que cette méthode

(function( $ ){

    var methods = {
        init : function(options) {

        },
        show : function( ) {    },// IS
        hide : function( ) {  },// GOOD
        update : function( content ) {  }// !!!
    };

    $.fn.tooltip = function(methodOrOptions) {
        if ( methods[methodOrOptions] ) {
            return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
            // Default to "init"
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  methodOrOptions + ' does not exist on jQuery.tooltip' );
        }    
    };


})( jQuery );

Fondamentalement, vous stockez vos fonctions dans un tableau (dans l'étendue de l'emballage de la fonction) et un contrôle de l'entrée, si le paramètre passé est une chaîne de caractères, le retour à une méthode par défaut ("init") si le paramètre est un objet (ou null).

Ensuite, vous pouvez appeler les méthodes comme si...

$('div').tooltip(); // calls the init method
$('div').tooltip({  // calls the init method
  foo : 'bar'
});
$('div').tooltip('hide'); // calls the hide method
$('div').tooltip('update', 'This is the new tooltip content!'); // calls the update method

Javascripts "arguments" de la variable est un tableau de tous les arguments passés de sorte qu'il fonctionne avec des longueurs arbitraires des paramètres de la fonction.

56voto

tvanfosson Points 268301

Voici le modèle que j'ai utilisé pour créer des plugins avec des méthodes supplémentaires. Vous l'utiliseriez comme:

 $('selector').myplugin( { key: 'value' } );
 

ou, pour appeler directement une méthode,

 $('selector').myplugin( 'mymethod1', 'argument' );
 

Exemple:

 ;(function($) {

    $.fn.extend({
        myplugin: function(options,arg) {
            if (options && typeof(options) == 'object') {
                options = $.extend( {}, $.myplugin.defaults, options );
            }

            // this creates a plugin for each element in
            // the selector or runs the function once per
            // selector.  To have it do so for just the
            // first element (once), return false after
            // creating the plugin to stop the each iteration 
            this.each(function() {
                new $.myplugin(this, options, arg );
            });
            return;
        }
    });

    $.myplugin = function( elem, options, arg ) {

        if (options && typeof(options) == 'string') {
           if (options == 'mymethod1') {
               myplugin_method1( arg );
           }
           else if (options == 'mymethod2') {
               myplugin_method2( arg );
           }
           return;
        }

        ...normal plugin actions...

        function myplugin_method1(arg)
        {
            ...do method1 with this and arg
        }

        function myplugin_method2(arg)
        {
            ...do method2 with this and arg
        }

    };

    $.myplugin.defaults = {
       ...
    };

})(jQuery);
 

35voto

CMS Points 315406

Qu'en est-il de cette approche:

 jQuery.fn.messagePlugin = function(){
    var selectedObjects = this;
    return {
             saySomething : function(message){
                              $(selectedObjects).each(function(){
                                $(this).html(message);
                              });
                              return selectedObjects; // Preserve the jQuery chainability 
                            },
             anotherAction : function(){
                               //...
                               return selectedObjects;
                             }
           };
}
// Usage:
$('p').messagePlugin().saySomething('I am a Paragraph').css('color', 'red');
 

Les objets sélectionnés sont stockés dans la fermeture de messagePlugin et cette fonction renvoie un objet contenant les fonctions associées au plug-in. Dans chaque fonction, vous pouvez effectuer les actions souhaitées sur les objets actuellement sélectionnés.

Vous pouvez tester et jouer avec le code ici .

Edit: code mis à jour pour préserver la puissance de la chaîne de caractères jQuery.

18voto

Kevin Jurkowski Points 210

Le problème actuellement sélectionnée réponse est que vous n'êtes pas en train de créer une nouvelle instance du plugin personnalisé pour chaque élément dans le sélecteur, comme vous pensez que vous êtes en train de faire... vous êtes seulement à la création d'une instance unique et passent dans le sélecteur de lui-même que le champ d'application.

La vue de ce violon pour une explication plus approfondie.

Au lieu de cela, vous aurez besoin d'une boucle sur le sélecteur à l'aide de jQuery.chaque et instancier une nouvelle instance du plugin personnalisé pour chaque élément dans le sélecteur.

Voici comment:

(function($) {

    var CustomPlugin = function($el, options) {

        this._defaults = {
            randomizer: Math.random()
        };

        this._options = $.extend(true, {}, this._defaults, options);

        this.options = function(options) {
            return (options) ?
                $.extend(true, this._options, options) :
                this._options;
        };

        this.move = function() {
            $el.css('margin-left', this._options.randomizer * 100);
        };

    };

    $.fn.customPlugin = function(methodOrOptions) {

        var method = (typeof methodOrOptions === 'string') ? methodOrOptions : undefined;

        if (method) {
            var customPlugins = [];

            function getCustomPlugin() {
                var $el          = $(this);
                var customPlugin = $el.data('customPlugin');

                customPlugins.push(customPlugin);
            }

            this.each(getCustomPlugin);

            var args    = (arguments.length > 1) ? Array.prototype.slice.call(arguments, 1) : undefined;
            var results = [];

            function applyMethod(index) {
                var customPlugin = customPlugins[index];

                if (!customPlugin) {
                    console.warn('$.customPlugin not instantiated yet');
                    console.info(this);
                    results.push(undefined);
                    return;
                }

                if (typeof customPlugin[method] === 'function') {
                    var result = customPlugin[method].apply(customPlugin, args);
                    results.push(result);
                } else {
                    console.warn('Method \'' + method + '\' not defined in $.customPlugin');
                }
            }

            this.each(applyMethod);

            return (results.length > 1) ? results : results[0];
        } else {
            var options = (typeof methodOrOptions === 'object') ? methodOrOptions : undefined;

            function init() {
                var $el          = $(this);
                var customPlugin = new CustomPlugin($el, options);

                $el.data('customPlugin', customPlugin);
            }

            return this.each(init);
        }

    };

})(jQuery);

Et un travail de violon.

Vous noterez que dans le premier violon, tous les divs sont toujours déplacé vers la droite le même nombre de pixels. C'est parce que seulement un objet d'options existe pour tous les éléments dans le sélecteur.

À l'aide de la technique de l'écrit ci-dessus, vous remarquerez que dans le second fiddle, chaque div n'est pas aligné et se déplace aléatoirement (à l'exclusion de la première div comme c'est aléatoire est toujours la valeur 1 sur la ligne 89). C'est parce que nous sommes désormais correctement l'instanciation d'un nouveau plugin personnalisé instance pour chaque élément dans le sélecteur. Chaque élément a ses propres options de l'objet et n'est pas enregistré dans le sélecteur, mais dans l'instance du plugin personnalisé lui-même.

Cela signifie que vous serez en mesure d'accéder aux méthodes de l'plugin personnalisé instancié sur un élément spécifique dans les DOM à partir de nouveaux sélecteurs jQuery et ne sont pas obligés de les mettre en cache, que vous seriez dans le premier violon.

Par exemple, ce serait de retourner un tableau de toutes les options des objets à l'aide de la technique dans le second violon. Il serait de retour indéfini dans la première.

$('div').customPlugin();
$('div').customPlugin('options'); // would return an array of all options objects

C'est de cette façon que vous auriez pour accéder aux options de l'objet dans le premier violon, et ne renvoie qu'un seul objet, pas un tableau d'entre eux:

var divs = $('div').customPlugin();
divs.customPlugin('options'); // would return a single options object

$('div').customPlugin('options');
// would return undefined, since it's not a cached selector

Je vous suggère en utilisant la technique ci-dessus, et non pas celui de la réponse choisie.

16voto

Yarin Points 18186

jQuery a rendu cela plus facile avec l'introduction de la Widget Factory .

Exemple:

 $.widget( "myNamespace.myPlugin", {

    options: {
        // Default options
    },

    _create: function() {
        // Initialization logic here
    },

    // Create a public method.
    myPublicMethod: function( argument ) {
        // ...
    },

    // Create a private method.
    _myPrivateMethod: function( argument ) {
        // ...
    }

});
 

Initialisation:

 $('#my-element').myPlugin();
$('#my-element').myPlugin( {defaultValue:10} );
 

Appel de méthode:

 $('#my-element').myPlugin('myPublicMethod', 20);
 

(Voici comment la bibliothèque d'interface utilisateur jQuery est construite.)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X