¿Cómo crear un complemento jQuery con métodos?

191

Estoy tratando de escribir un complemento jQuery que proporcionará funciones / métodos adicionales al objeto que lo llama. Todos los tutoriales que leí en línea (he estado navegando durante las últimas 2 horas) incluyen, como máximo, cómo agregar opciones, pero no funciones adicionales.

Esto es lo que estoy buscando hacer:

// formatee div para que sea un contenedor de mensajes llamando al complemento para ese div

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

O algo por el estilo. Esto es a lo que se reduce: llamo al complemento, luego llamo a una función asociada con ese complemento. Parece que no puedo encontrar una manera de hacer esto, y he visto muchos complementos hacerlo antes.

Esto es lo que tengo hasta ahora para el complemento:

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);
  }
};

¿Cómo puedo lograr algo así?

¡Gracias!


Actualización 18 de noviembre de 2013: he cambiado la respuesta correcta a la de los siguientes comentarios y votos a favor de Hari.

Yuval Karmi
fuente

Respuestas:

310

De acuerdo con la página de creación de complementos de jQuery ( http://docs.jquery.com/Plugins/Authoring ), es mejor no enturbiar los espacios de nombres jQuery y jQuery.fn. Sugieren este método:

(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 );

Básicamente, almacena sus funciones en una matriz (dentro del alcance de la función de ajuste) y verifica si hay una entrada si el parámetro pasado es una cadena, volviendo a un método predeterminado ("init" aquí) si el parámetro es un objeto (o nulo).

Entonces puedes llamar a los métodos así ...

$('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

La variable "argumentos" de Javascripts es una matriz de todos los argumentos pasados, por lo que funciona con longitudes arbitrarias de parámetros de función.

Hari Karam Singh
fuente
2
Este es el método que uso. También puede llamar a los métodos de forma estática a través de $ .fn.tooltip ('nombre del método', params);
Rake36
1
Arquitectura muy práctica. También agregué esta línea antes de llamar al método init: this.data('tooltip', $.extend(true, {}, $.fn.tooltip.defaults, methodOrOptions));así que ahora puedo acceder a las opciones cuando quiera después de la inicialización.
ivkremer
16
Para cualquiera como yo que primero dijo "de dónde vino la variable de argumentos" - developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… - He estado usando JS para siempre y nunca lo supe. ¡Tu aprendes algo nuevo cada dia!
streetlogics
2
@ Dih, estoy contigo en este caso. Este enfoque parece genial, pero no le da acceso a su configuración global desde ningún otro lugar init.
Stephen Collins el
44
¡Hay un gran problema con esta técnica! No crea una nueva instancia para cada elemento en el selector como cree que está haciendo, sino que crea una sola instancia adjunta al selector en sí. Ver mi respuesta para una solución.
Kevin Jurkowski
56

Aquí está el patrón que he usado para crear complementos con métodos adicionales. Lo usarías como:

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

o, para invocar un método directamente,

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

Ejemplo:

;(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);
tvanfosson
fuente
9
mismo patrón que jquery-ui, no me gustan todas las cuerdas mágicas, pero ¿hay alguna otra manera?
redsquare
8
Esto parece una forma no estándar de hacer las cosas: ¿hay algo más simple que esto, como encadenar funciones? ¡gracias!
Yuval Karmi el
2
@yuval: por lo general, los complementos jQuery devuelven jQuery o un valor, no el complemento en sí. Es por eso que el nombre del método se pasa como argumento al complemento cuando desea invocar el complemento. Puede pasar cualquier número de argumentos, pero tendrá que ajustar las funciones y el análisis de argumentos. Probablemente sea mejor configurarlos en un objeto anónimo como lo mostró.
tvanfosson
1
¿Cuál es el significado de ;en tu primera línea?
explícame
44
@GusDeCooL solo se asegura de que estamos comenzando una nueva declaración para que nuestra definición de función no se interprete como un argumento para el JavaScript mal formateado de otra persona (es decir, el parren inicial no se toma como un operador de invocación de función). Ver stackoverflow.com/questions/7365172/…
tvanfosson el
35

¿Qué pasa con este enfoque?

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');

Los objetos seleccionados se almacenan en el mensaje de cierre del complemento, y esa función devuelve un objeto que contiene las funciones asociadas con el complemento, en cada función puede realizar las acciones deseadas a los objetos seleccionados actualmente.

Puedes probar y jugar con el código aquí .

Editar: Código actualizado para preservar el poder de la cadena de jQuery.

CMS
fuente
1
Me está costando un poco entender cómo se vería esto. Suponiendo que tengo un código que debe ejecutarse la primera vez que se ejecuta, primero tendré que inicializarlo en mi código, algo como esto: $ ('p'). MessagePlugin (); luego, más adelante en el código, me gustaría llamar a la función saySomething like this $ ('p'). messagePlugin (). saySomething ('something'); ¿esto no reiniciará el complemento y luego llamará a la función? ¿Cómo sería esto con el gabinete y las opciones? muchas gracias. -yuval
Yuval Karmi
1
Sin embargo, de alguna manera rompe el paradigma de la posibilidad de conectividad de jQuery.
tvanfosson
tal vez esta debería ser la mejor respuesta
Dragouf
3
Cada vez que llame a messagePlugin () creará un nuevo objeto con esas dos funciones, ¿no?
w00t
44
El problema principal con este enfoque es que no puede preservar la posibilidad de seguir la cadena a $('p').messagePlugin()menos que llame a una de las dos funciones que devuelve.
Joshua Bambrick
18

El problema con la respuesta seleccionada actualmente es que en realidad no está creando una nueva instancia del complemento personalizado para cada elemento en el selector como cree que está haciendo ... en realidad solo está creando una única instancia y pasando el selector en sí como el alcance.

Vea este violín para una explicación más profunda.

En su lugar, deberá recorrer el selector utilizando jQuery.each e instanciar una nueva instancia del complemento personalizado para cada elemento del selector.

Así es cómo:

(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);

Y un violín de trabajo .

Notarás cómo en el primer violín, todos los divs siempre se mueven a la derecha exactamente el mismo número de píxeles. Esto se debe a que solo existe un objeto de opciones para todos los elementos en el selector.

Usando la técnica escrita anteriormente, notará que en el segundo violín, cada div no está alineado y se mueve aleatoriamente (excluyendo el primer div ya que su aleatorizador siempre se establece en 1 en la línea 89). Esto se debe a que ahora estamos instanciando correctamente una nueva instancia de complemento personalizada para cada elemento en el selector. Cada elemento tiene su propio objeto de opciones y no se guarda en el selector, sino en la instancia del complemento personalizado.

Esto significa que podrá acceder a los métodos del complemento personalizado instanciado en un elemento específico en el DOM desde nuevos selectores jQuery y no estará obligado a almacenarlos en caché, como lo estaría en el primer violín.

Por ejemplo, esto devolvería una matriz de todos los objetos de opciones utilizando la técnica en el segundo violín. Volvería indefinido en el primero.

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

Así es como tendría que acceder al objeto de opciones en el primer violín, y solo devolvería un solo objeto, no una matriz de ellos:

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

Sugeriría usar la técnica anterior, no la de la respuesta seleccionada actualmente.

Kevin Jurkowski
fuente
Gracias, esto me ayudó mucho, particularmente introduciéndome el método .data (). Muy útil. FWIW también puede simplificar parte de su código utilizando métodos anónimos.
dalemac
jQuery chainability no funciona con este método ... $('.my-elements').find('.first-input').customPlugin('update'‌​, 'first value').end().find('.second-input').customPlugin('update', 'second value'); returns Cannot read property 'end' of undefined. jsfiddle.net/h8v1k2pL
Alex G
16

jQuery ha hecho esto mucho más fácil con la introducción de Widget Factory .

Ejemplo:

$.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 ) {
        // ...
    }

});

Inicializacion:

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

Método de llamada:

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

(Así es como se construye la biblioteca jQuery UI ).

Yarin
fuente
@ daniel.sedlacek a) "arquitectura muy mala" - es la arquitectura de widgets estándar de jQuery b) "se verificó la integridad en tiempo de compilación" - JavaScript es un lenguaje dinámico c) "TypeScript" - ¿qué?
Yarin
a) ese es el argumento ad populum, b) cada mejor JS IDE tiene código de finalización o linting, c) google
daniel.sedlacek
Eso es pura ilusión, señor Sedlacek.
mystrdat
Por documentos: este sistema se llama Widget Factory y se expone como jQuery.widget como parte de jQuery UI 1.8; sin embargo, se puede usar independientemente de jQuery UI. ¿Cómo se usa $ .widget sin jQuery UI?
Airn5475
13

Un enfoque más simple es usar funciones anidadas. Luego puede encadenarlos de forma orientada a objetos. Ejemplo:

jQuery.fn.MyPlugin = function()
{
  var _this = this;
  var a = 1;

  jQuery.fn.MyPlugin.DoSomething = function()
  {
    var b = a;
    var c = 2;

    jQuery.fn.MyPlugin.DoSomething.DoEvenMore = function()
    {
      var d = a;
      var e = c;
      var f = 3;
      return _this;
    };

    return _this;
  };

  return this;
};

Y aquí está cómo llamarlo:

var pluginContainer = $("#divSomeContainer");
pluginContainer.MyPlugin();
pluginContainer.MyPlugin.DoSomething();
pluginContainer.MyPlugin.DoSomething.DoEvenMore();

Pero ten cuidado. No puede llamar a una función anidada hasta que se haya creado. Entonces no puedes hacer esto:

var pluginContainer = $("#divSomeContainer");
pluginContainer.MyPlugin();
pluginContainer.MyPlugin.DoSomething.DoEvenMore();
pluginContainer.MyPlugin.DoSomething();

La función DoEvenMore ni siquiera existe porque la función DoSomething aún no se ha ejecutado, lo cual es necesario para crear la función DoEvenMore. Para la mayoría de los complementos de jQuery, realmente solo tendrá un nivel de funciones anidadas y no dos, como he mostrado aquí.
Solo asegúrese de que cuando cree funciones anidadas, defina estas funciones al comienzo de su función principal antes de que se ejecute cualquier otro código en la función principal.

Finalmente, tenga en cuenta que el miembro "this" se almacena en una variable llamada "_this". Para funciones anidadas, debe devolver "_this" si necesita una referencia a la instancia en el cliente que realiza la llamada. No puede simplemente devolver "esto" en la función anidada porque eso devolverá una referencia a la función y no a la instancia de jQuery. Devolver una referencia de jQuery le permite encadenar métodos intrínsecos de jQuery al regresar.

Polaris431
fuente
2
Esto es genial, solo me pregunto por qué jQuery parece favorecer llamar a los métodos por su nombre como en el patrón .plugin ('método').
w00t
66
Esto no funciona. Si invoca el complemento en dos contenedores diferentes, las variables internas se anulan (es decir, esto)
mbrochh
Error: no permite pluginContainer.MyPlugin.DoEvenMore (). DoSomething ();
Paul Swetz
9

Lo obtuve de jQuery Plugin Boilerplate

También descrito en jQuery Plugin Boilerplate, repita

// jQuery Plugin Boilerplate
// A boilerplate for jumpstarting jQuery plugins development
// version 1.1, May 14th, 2011
// by Stefan Gabos

// remember to change every instance of "pluginName" to the name of your plugin!
(function($) {

    // here we go!
    $.pluginName = function(element, options) {

    // plugin's default options
    // this is private property and is accessible only from inside the plugin
    var defaults = {

        foo: 'bar',

        // if your plugin is event-driven, you may provide callback capabilities
        // for its events. execute these functions before or after events of your
        // plugin, so that users may customize those particular events without
        // changing the plugin's code
        onFoo: function() {}

    }

    // to avoid confusions, use "plugin" to reference the
    // current instance of the object
    var plugin = this;

    // this will hold the merged default, and user-provided options
    // plugin's properties will be available through this object like:
    // plugin.settings.propertyName from inside the plugin or
    // element.data('pluginName').settings.propertyName from outside the plugin,
    // where "element" is the element the plugin is attached to;
    plugin.settings = {}

    var $element = $(element), // reference to the jQuery version of DOM element
    element = element; // reference to the actual DOM element

    // the "constructor" method that gets called when the object is created
    plugin.init = function() {

    // the plugin's final properties are the merged default and
    // user-provided options (if any)
    plugin.settings = $.extend({}, defaults, options);

    // code goes here

   }

   // public methods
   // these methods can be called like:
   // plugin.methodName(arg1, arg2, ... argn) from inside the plugin or
   // element.data('pluginName').publicMethod(arg1, arg2, ... argn) from outside
   // the plugin, where "element" is the element the plugin is attached to;

   // a public method. for demonstration purposes only - remove it!
   plugin.foo_public_method = function() {

   // code goes here

    }

     // private methods
     // these methods can be called only from inside the plugin like:
     // methodName(arg1, arg2, ... argn)

     // a private method. for demonstration purposes only - remove it!
     var foo_private_method = function() {

        // code goes here

     }

     // fire up the plugin!
     // call the "constructor" method
     plugin.init();

     }

     // add the plugin to the jQuery.fn object
     $.fn.pluginName = function(options) {

        // iterate through the DOM elements we are attaching the plugin to
        return this.each(function() {

          // if plugin has not already been attached to the element
          if (undefined == $(this).data('pluginName')) {

              // create a new instance of the plugin
              // pass the DOM element and the user-provided options as arguments
              var plugin = new $.pluginName(this, options);

              // in the jQuery version of the element
              // store a reference to the plugin object
              // you can later access the plugin and its methods and properties like
              // element.data('pluginName').publicMethod(arg1, arg2, ... argn) or
              // element.data('pluginName').settings.propertyName
              $(this).data('pluginName', plugin);

           }

        });

    }

})(jQuery);
MaxEcho
fuente
Su método rompe el encadenamiento de jQuery: $('.first-input').data('pluginName').publicMethod('new value').css('color', red);devuelve Cannot read property 'css' of undefined jsfiddle.net/h8v1k2pL/1
Alex G
@AlexG dado este ejemplo que agregaría, return $elementen este ejemplo lo cambiaría a plugin.foo_public_method = function() {/* Your Code */ return $element;}@Salim gracias por ayudarme ... github.com/AndreaLombardo/BootSideMenu/pull/34
CrandellWS
6

Demasiado tarde, pero tal vez pueda ayudar a alguien algún día.

Estaba en la misma situación, creando un complemento jQuery con algunos métodos, y después de leer algunos artículos y algunos neumáticos, creo una plantilla de plugin jQuery ( https://github.com/acanimal/jQuery-Plugin-Boilerplate ).

Además, desarrollé con él un complemento para administrar etiquetas ( https://github.com/acanimal/tagger.js ) y escribí dos publicaciones en el blog explicando paso a paso la creación de un complemento jQuery ( http: // acuriousanimal. com / blog / 2013/01/15 / things-i-learn-creating-a-jquery-plugin-part-i / ).

EricSonaron
fuente
posiblemente la mejor publicación que he encontrado hasta ahora sobre la creación de complementos jQuery como principiante - gracias;)
Dex Dave
5

Tu puedes hacer:

(function($) {
  var YourPlugin = function(element, option) {
    var defaults = {
      //default value
    }

    this.option = $.extend({}, defaults, option);
    this.$element = $(element);
    this.init();
  }

  YourPlugin.prototype = {
    init: function() { },
    show: function() { },
    //another functions
  }

  $.fn.yourPlugin = function(option) {
    var arg = arguments,
        options = typeof option == 'object' && option;;
    return this.each(function() {
      var $this = $(this),
          data = $this.data('yourPlugin');

      if (!data) $this.data('yourPlugin', (data = new YourPlugin(this, options)));
      if (typeof option === 'string') {
        if (arg.length > 1) {
          data[option].apply(data, Array.prototype.slice.call(arg, 1));
        } else {
          data[option]();
        }
      }
    });
  };
});

De esta manera, su objeto de plugins se almacena como valor de datos en su elemento.

//Initialization without option
$('#myId').yourPlugin();

//Initialization with option
$('#myId').yourPlugin({
  // your option
});

// call show method
$('#myId').yourPlugin('show');
Mazaher Bazari
fuente
3

¿Qué pasa con el uso de disparadores? ¿Alguien sabe algún inconveniente al usarlos? El beneficio es que todas las variables internas son accesibles a través de los disparadores, y el código es muy simple.

Ver en jsfiddle .

Ejemplo de uso

<div id="mydiv">This is the message container...</div>

<script>
    var mp = $("#mydiv").messagePlugin();

    // the plugin returns the element it is called on
    mp.trigger("messagePlugin.saySomething", "hello");

    // so defining the mp variable is not needed...
    $("#mydiv").trigger("messagePlugin.repeatLastMessage");
</script>

Enchufar

jQuery.fn.messagePlugin = function() {

    return this.each(function() {

        var lastmessage,
            $this = $(this);

        $this.on('messagePlugin.saySomething', function(e, message) {
            lastmessage = message;
            saySomething(message);
        });

        $this.on('messagePlugin.repeatLastMessage', function(e) {
            repeatLastMessage();
        });

        function saySomething(message) {
            $this.html("<p>" + message + "</p>");
        }

        function repeatLastMessage() {
            $this.append('<p>Last message was: ' + lastmessage + '</p>');
        }

    });

}
István Ujj-Mészáros
fuente
1
cf. tu comentario. El único problema que veo aquí es posiblemente un mal uso del sistema de eventos. Es atípico usar eventos simplemente para invocar una función; parece excesivo y puede romperse fácilmente. Normalmente, usaría los eventos de manera de publicación-suscripción, por ejemplo, una función publica que se ha producido alguna condición "A". Otras entidades, interesadas en "A", escuchan el mensaje de que "A" ha sucedido, luego hacen algo. Parece que lo estás usando como "comando" push, pero suponiendo que solo haya un oyente. Debes tener cuidado de que tu semántica no se rompa al agregar (otros) oyentes.
tvanfosson
@tvanfosson Gracias por tu comentario. Entiendo que no es una técnica común y puede causar problemas si alguien agrega accidentalmente un detector de eventos, pero si lleva el nombre del complemento, entonces es muy poco probable. No conozco ningún problema relacionado con el rendimiento, pero el código en sí parece ser mucho más simple para mí que con las otras soluciones, pero es posible que me falte algo.
István Ujj-Mészáros
3

Aquí quiero sugerir pasos para crear un complemento simple con argumentos.

(function($) {
  $.fn.myFirstPlugin = function(options) {
    // Default params
    var params = $.extend({
      text     : 'Default Title',
      fontsize : 10,
    }, options);
    return $(this).text(params.text);
  }
}(jQuery));

$('.cls-title').myFirstPlugin({ text : 'Argument Title' });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 class="cls-title"></h1>

Aquí, hemos agregado un objeto predeterminado llamado paramsy establecemos valores predeterminados de opciones usando la extendfunción. Por lo tanto, si pasamos un argumento en blanco, establecerá valores predeterminados;

Leer más: Cómo crear el complemento JQuery

Gopal Joshi
fuente
Hola Gopal Joshi, por favor, dale al siguiente nivel la creación del complemento jquery. Esperamos de su respuesta necesaria.
Sakthi Karthik
Hola @SakthiKarthik, Off cource Publicaré un nuevo tutorial pronto en mi blog
Gopal Joshi,
1
Hola @SakthiKarthik, puedes consultar un nuevo artículo sobre el plugin jquery del siguiente nivel aquí sgeek.org/…
Gopal Joshi
2

Prueba este:

$.fn.extend({
"calendar":function(){
    console.log(this);
    var methods = {
            "add":function(){console.log("add"); return this;},
            "init":function(){console.log("init"); return this;},
            "sample":function(){console.log("sample"); return this;}
    };

    methods.init(); // you can call any method inside
    return methods;
}}); 
$.fn.calendar() // caller or 
$.fn.calendar().sample().add().sample() ......; // call methods
Serkan KONAKCI
fuente
1

Aquí está mi versión básica de esto. Similar a los publicados anteriormente, llamaría como:

$('#myDiv').MessagePlugin({ yourSettings: 'here' })
           .MessagePlugin('saySomething','Hello World!');

-o acceda a la instancia directamente @ plugin_MessagePlugin

$elem = $('#myDiv').MessagePlugin();
var instance = $elem.data('plugin_MessagePlugin');
instance.saySomething('Hello World!');

MessagePlugin.js

;(function($){

    function MessagePlugin(element,settings){ // The Plugin
        this.$elem = element;
        this._settings = settings;
        this.settings = $.extend(this._default,settings);
    }

    MessagePlugin.prototype = { // The Plugin prototype
        _default: {
            message: 'Generic message'
        },
        initialize: function(){},
        saySomething: function(message){
            message = message || this._default.message;
            return this.$elem.html(message);
        }
    };

    $.fn.MessagePlugin = function(settings){ // The Plugin call

        var instance = this.data('plugin_MessagePlugin'); // Get instance

        if(instance===undefined){ // Do instantiate if undefined
            settings = settings || {};
            this.data('plugin_MessagePlugin',new MessagePlugin(this,settings));
            return this;
        }

        if($.isFunction(MessagePlugin.prototype[settings])){ // Call method if argument is name of method
            var args = Array.prototype.slice.call(arguments); // Get the arguments as Array
            args.shift(); // Remove first argument (name of method)
            return MessagePlugin.prototype[settings].apply(instance, args); // Call the method
        }

        // Do error handling

        return this;
    }

})(jQuery);
jtrumbull
fuente
1

La siguiente estructura de plugin utiliza el método jQuerydata() para proporcionar una interfaz pública a los métodos / ajustes internos del plugin (al tiempo que preserva la posibilidad de jQuery):

(function($, window, undefined) { 
  const defaults = {
    elementId   : null,
    shape       : "square",
    color       : "aqua",
    borderWidth : "10px",
    borderColor : "DarkGray"
  };

  $.fn.myPlugin = function(options) {
    // settings, e.g.:  
    var settings = $.extend({}, defaults, options);

    // private methods, e.g.:
    var setBorder = function(color, width) {        
      settings.borderColor = color;
      settings.borderWidth = width;          
      drawShape();
    };

    var drawShape = function() {         
      $('#' + settings.elementId).attr('class', settings.shape + " " + "center"); 
      $('#' + settings.elementId).css({
        'background-color': settings.color,
        'border': settings.borderWidth + ' solid ' + settings.borderColor      
      });
      $('#' + settings.elementId).html(settings.color + " " + settings.shape);            
    };

    return this.each(function() { // jQuery chainability     
      // set stuff on ini, e.g.:
      settings.elementId = $(this).attr('id'); 
      drawShape();

      // PUBLIC INTERFACE 
      // gives us stuff like: 
      //
      //    $("#...").data('myPlugin').myPublicPluginMethod();
      //
      var myPlugin = {
        element: $(this),
        // access private plugin methods, e.g.: 
        setBorder: function(color, width) {        
          setBorder(color, width);
          return this.element; // To ensure jQuery chainability 
        },
        // access plugin settings, e.g.: 
        color: function() {
          return settings.color;
        },        
        // access setting "shape" 
        shape: function() {
          return settings.shape;
        },     
        // inspect settings 
        inspectSettings: function() {
          msg = "inspecting settings for element '" + settings.elementId + "':";   
          msg += "\n--- shape: '" + settings.shape + "'";
          msg += "\n--- color: '" + settings.color + "'";
          msg += "\n--- border: '" + settings.borderWidth + ' solid ' + settings.borderColor + "'";
          return msg;
        },               
        // do stuff on element, e.g.:  
        change: function(shape, color) {        
          settings.shape = shape;
          settings.color = color;
          drawShape();   
          return this.element; // To ensure jQuery chainability 
        }
      };
      $(this).data("myPlugin", myPlugin);
    }); // return this.each 
  }; // myPlugin
}(jQuery));

Ahora puede llamar a los métodos internos del complemento para acceder o modificar los datos del complemento o el elemento relevante utilizando esta sintaxis:

$("#...").data('myPlugin').myPublicPluginMethod(); 

Siempre que devuelva el elemento actual (esto) desde el interior de su implementación de myPublicPluginMethod()jQuery-chainability se conservará, por lo que funciona lo siguiente:

$("#...").data('myPlugin').myPublicPluginMethod().css("color", "red").html("...."); 

Estos son algunos ejemplos (para obtener detalles, consulte este violín ):

// initialize plugin on elements, e.g.:
$("#shape1").myPlugin({shape: 'square', color: 'blue', borderColor: 'SteelBlue'});
$("#shape2").myPlugin({shape: 'rectangle', color: 'red', borderColor: '#ff4d4d'});
$("#shape3").myPlugin({shape: 'circle', color: 'green', borderColor: 'LimeGreen'});

// calling plugin methods to read element specific plugin settings:
console.log($("#shape1").data('myPlugin').inspectSettings());    
console.log($("#shape2").data('myPlugin').inspectSettings());    
console.log($("#shape3").data('myPlugin').inspectSettings());      

// calling plugin methods to modify elements, e.g.:
// (OMG! And they are chainable too!) 
$("#shape1").data('myPlugin').change("circle", "green").fadeOut(2000).fadeIn(2000);      
$("#shape1").data('myPlugin').setBorder('LimeGreen', '30px');

$("#shape2").data('myPlugin').change("rectangle", "red"); 
$("#shape2").data('myPlugin').setBorder('#ff4d4d', '40px').css({
  'width': '350px',
  'font-size': '2em' 
}).slideUp(2000).slideDown(2000);              

$("#shape3").data('myPlugin').change("square", "blue").fadeOut(2000).fadeIn(2000);   
$("#shape3").data('myPlugin').setBorder('SteelBlue', '30px');

// etc. ...     
Mayinx
fuente
0

En realidad, esto se puede hacer que funcione de una manera "agradable" usando defineProperty. Donde "agradable" significa sin tener que usar ()para obtener el espacio de nombres del complemento ni tener que pasar el nombre de la función por cadena.

Compatibilidad nit: defineProperty no funciona en navegadores antiguos como IE8 y versiones inferiores. Advertencia: $.fn.color.blue.apply(foo, args) no funcionará, debes usarlo foo.color.blue.apply(foo, args).

function $_color(color)
{
    return this.css('color', color);
}

function $_color_blue()
{
    return this.css('color', 'blue');
}

Object.defineProperty($.fn, 'color',
{
    enumerable: true,
    get: function()
    {
        var self = this;

        var ret = function() { return $_color.apply(self, arguments); }
        ret.blue = function() { return $_color_blue.apply(self, arguments); }

        return ret;
    }
});

$('#foo').color('#f00');
$('#bar').color.blue();

Enlace JSFiddle

kralyk
fuente
0

De acuerdo con el estándar jquery, puede crear el complemento de la siguiente manera:

(function($) {

    //methods starts here....
    var methods = {
        init : function(method,options) {
             this.loadKeywords.settings = $.extend({}, this.loadKeywords.defaults, options);
             methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
             $loadkeywordbase=$(this);
        },
        show : function() {
            //your code here.................
        },
        getData : function() {
           //your code here.................
        }

    } // do not put semi colon here otherwise it will not work in ie7
    //end of methods

    //main plugin function starts here...
    $.fn.loadKeywords = function(options,method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(
                    arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not ecw-Keywords');
        }
    };
    $.fn.loadKeywords.defaults = {
            keyName:     'Messages',
            Options:     '1',
            callback: '',
    };
    $.fn.loadKeywords.settings = {};
    //end of plugin keyword function.

})(jQuery);

¿Cómo llamar a este complemento?

1.$('your element').loadKeywords('show',{'callback':callbackdata,'keyName':'myKey'}); // show() will be called

Referencia: enlace

Mahesh
fuente
0

Creo que esto podría ayudarte ...

(function ( $ ) {
  
    $.fn.highlight = function( options ) {
  
        // This is the easiest way to have default options.
        var settings = $.extend({
            // These are the defaults.
            color: "#000",
            backgroundColor: "yellow"
        }, options );
  
        // Highlight the collection based on the settings variable.
        return this.css({
            color: settings.color,
            backgroundColor: settings.backgroundColor
        });
  
    };
  
}( jQuery ));

En el ejemplo anterior, creé un simple complemento jquery highlight . Compartí un artículo en el que discutí sobre Cómo crear su propio complemento jQuery de Basic a Advance. Creo que deberías echarle un vistazo ... http://mycodingtricks.com/jquery/how-to-create-your-own-jquery-plugin/

Shubham Kumar
fuente
0

A continuación se incluye un pequeño complemento para tener un método de advertencia para la depuración. Mantenga este código en el archivo jquery.debug.js: JS:

jQuery.fn.warning = function() {
   return this.each(function() {
      alert('Tag Name:"' + $(this).prop("tagName") + '".');
   });
};

HTML:

<html>
   <head>
      <title>The jQuery Example</title>

      <script type = "text/javascript" 
         src = "http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

      <script src = "jquery.debug.js" type = "text/javascript"></script>

      <script type = "text/javascript" language = "javascript">
         $(document).ready(function() {
            $("div").warning();
            $("p").warning();
         });
      </script> 
   </head>

   <body>
      <p>This is paragraph</p>
      <div>This is division</div>
   </body>

</html>
jayaweb
fuente
0

Así es como lo hago:

(function ( $ ) {

$.fn.gridview = function( options ) {

    ..........
    ..........


    var factory = new htmlFactory();
    factory.header(...);

    ........

};

}( jQuery ));


var htmlFactory = function(){

    //header
     this.header = function(object){
       console.log(object);
  }
 }
Mina Gabriel
fuente
-2

Lo que hiciste es básicamente extender el objeto jQuery.fn.messagePlugin por un nuevo método. Lo cual es útil pero no en tu caso.

Tienes que hacer es usar esta técnica

function methodA(args){ this // refers to object... }
function saySomething(message){ this.html(message);  to first function }

jQuery.fn.messagePlugin = function(opts) {
  if(opts=='methodA') methodA.call(this);
  if(opts=='saySomething') saySomething.call(this, arguments[0]); // arguments is an array of passed parameters
  return this.each(function(){
    alert(this);
  });

};

Pero puede lograr lo que quiera. Quiero decir que hay una manera de hacer $ ("# mydiv"). MessagePlugin (). SaySomething ("hola"); Mi amigo, él comenzó a escribir sobre lugins y cómo extenderlos con su cadena de funcionalidades aquí está el enlace a su blog

James
fuente