Como criar um plugin jQuery com métodos?

191

Estou tentando escrever um plugin jQuery que fornecerá funções / métodos adicionais para o objeto que o chama. Todos os tutoriais que li on-line (navegando nas últimas 2 horas) incluem, no máximo, como adicionar opções, mas não funções adicionais.

Aqui está o que eu estou procurando fazer:

// formata div para ser um contêiner de mensagem chamando o plug-in para essa div

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

Ou algo nesse sentido. Aqui está o que se resume a: Eu chamo o plug-in, depois chamo uma função associada a ele. Não consigo encontrar uma maneira de fazer isso, e já vi muitos plugins fazer isso antes.

Aqui está o que eu tenho até agora para o 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);
  }
};

Como posso conseguir algo assim?

Obrigado!


Atualização em 18 de novembro de 2013: Alterei a resposta correta para a dos seguintes comentários e votos positivos de Hari.

Yuval Karmi
fonte

Respostas:

310

De acordo com a página de criação do plug-in do jQuery ( http://docs.jquery.com/Plugins/Authoring ), é melhor não confundir os namespaces do jQuery e do jQuery.fn. Eles sugerem 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 );

Basicamente, você armazena suas funções em uma matriz (com escopo definido para a função de quebra automática) e verifica uma entrada se o parâmetro passado for uma string, revertendo para um método padrão ("init" aqui) se o parâmetro for um objeto (ou nulo).

Então você pode chamar os métodos assim ...

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

A variável "argumentos" do Javascripts é uma matriz de todos os argumentos passados, portanto funciona com comprimentos arbitrários de parâmetros de função.

Hari Karam Singh
fonte
2
Este é o método que eu uso. Você também pode chamar os métodos de forma estática via $ .fn.tooltip ('methodname', params);
precisa saber é o seguinte
1
Arquitetura muito útil. Também adicionei esta linha antes de chamar o método init:, this.data('tooltip', $.extend(true, {}, $.fn.tooltip.defaults, methodOrOptions));para que agora eu possa acessar as opções sempre que desejar após a inicialização.
Ivkremer 7/08
16
Para alguém como eu que disse pela primeira vez "de onde vem a variável argumentos" - developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/… - eu uso o JS para sempre e nunca soube disso. Você aprende algo novo a cada dia!
Streetlogics 19/08/2013
2
@ DiH, estou com você neste. Essa abordagem parece ótima, mas não fornece acesso às suas configurações globais de nenhum outro lugar init.
Stephen Collins
4
Há um grande problema com essa técnica! Ele não cria uma nova instância para cada elemento do seletor como você pensa que está fazendo; em vez disso, cria apenas uma única instância anexada ao próprio seletor. Veja minha resposta para uma solução.
precisa saber é o seguinte
56

Aqui está o padrão que eu usei para criar plugins com métodos adicionais. Você usaria como:

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

ou, para invocar um método diretamente,

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

Exemplo:

;(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
fonte
9
mesmo padrão que jquery-ui, eu não gosto de todas as cordas mágicas, mas existe alguma outra maneira!
redsquare
8
isso parece uma maneira não-padrão de fazer as coisas - há algo mais simples que isso, como encadear funções? obrigado!
Yuval Karmi 12/07/2009
2
@yuval - normalmente os plugins jQuery retornam jQuery ou um valor, não o próprio plugin. É por isso que o nome do método é passado como argumento para o plug-in quando você deseja invocá-lo. Você pode passar qualquer número de argumentos, mas precisará ajustar as funções e a análise de argumentos. Provavelmente, é melhor configurá-los em um objeto anônimo, como você mostrou.
tvanfosson
1
Qual é o significado da ;sua primeira linha? por favor me explicar :)
GusDeCooL
4
@GusDeCooL apenas garante que estamos iniciando uma nova instrução para que nossa definição de função não seja interpretada como um argumento para o Javascript mal formatado de outra pessoa (ou seja, o paren inicial não é considerado um operador de chamada de função). Veja stackoverflow.com/questions/7365172/…
tvanfosson
35

E essa abordagem:

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

Os objetos selecionados são armazenados no fechamento messagePlugin e essa função retorna um objeto que contém as funções associadas ao plug-in, em cada função você pode executar as ações desejadas nos objetos selecionados no momento.

Você pode testar e jogar com o código aqui .

Editar: código atualizado para preservar o poder da capacidade de cadeia do jQuery.

CMS
fonte
1
Estou tendo um pouco de dificuldade para entender como isso seria. Supondo que eu tenha um código que precise ser executado na primeira vez em que for executado, terei que inicializá-lo primeiro no meu código - algo como isto: $ ('p'). MessagePlugin (); mais tarde, no código, eu gostaria de chamar a função saySomething como este $ ('p'). messagePlugin (). saySomething ('something'); isso não reinicializará o plug-in e depois chamará a função? como seria isso com o gabinete e as opções? Muito obrigado. -yuval
Yuval Karmi
1
Porém, meio que quebra o paradigma de cadeia do jQuery.
Tvanfosson
talvez esta deve ser a melhor resposta
Dragouf
3
Toda vez que você chama messagePlugin (), ele cria um novo objeto com essas duas funções, não?
W00t
4
O principal problema dessa abordagem é que ela não pode preservar a sequência de encadeamento, a $('p').messagePlugin()menos que você chame uma das duas funções que ela retorna.
Joshua Bambrick
18

O problema com a resposta atualmente selecionada é que você não está realmente criando uma nova instância do plug-in personalizado para cada elemento do seletor como pensa que está fazendo ... na verdade, está apenas criando uma única instância e transmitindo o próprio seletor como o escopo.

Veja este violino para uma explicação mais profunda.

Em vez disso, você precisará percorrer o seletor usando jQuery.each e instanciar uma nova instância do plug-in personalizado para cada elemento no seletor.

Aqui está como:

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

E um violino de trabalho .

Você notará como, no primeiro violino, todas as divs são sempre movidas para a direita exatamente o mesmo número de pixels. Isso ocorre porque apenas um objeto de opções existe para todos os elementos no seletor.

Usando a técnica descrita acima, você notará que, no segundo violino, cada div não está alinhada e é movida aleatoriamente (excluindo a primeira div, pois o randomizador é sempre definido como 1 na linha 89). Isso ocorre porque agora estamos instanciando adequadamente uma nova instância de plug-in personalizado para cada elemento no seletor. Cada elemento possui seu próprio objeto de opções e não é salvo no seletor, mas na instância do próprio plug-in customizado.

Isso significa que você poderá acessar os métodos do plug-in personalizado instanciado em um elemento específico no DOM a partir de novos seletores do jQuery e não será forçado a armazená-los, como faria no primeiro violão.

Por exemplo, isso retornaria uma matriz de todos os objetos de opções usando a técnica no segundo violino. Ele retornaria indefinido no primeiro.

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

É assim que você teria que acessar o objeto de opções no primeiro violino e retornaria apenas um único objeto, não uma matriz deles:

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

Eu sugiro usar a técnica acima, não a da resposta atualmente selecionada.

Kevin Jurkowski
fonte
Obrigado, isso me ajudou muito, principalmente introduzindo o método .data () para mim. Muito conveniente. FWIW, você também pode simplificar parte do seu código usando métodos anônimos.
precisa saber é o seguinte
jQuery chainability não está funcionando usando esse 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

O jQuery tornou isso muito mais fácil com a introdução da Widget Factory .

Exemplo:

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

});

Inicialização:

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

Chamada de método:

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

(É assim que a biblioteca da UI do jQuery é criada.)

Yarin
fonte
@ daniel.sedlacek a) "arquitetura muito ruim" - é a arquitetura padrão de widgets do jQuery b) "verificada a integridade no tempo de compilação" - JavaScript é uma linguagem dinâmica c) "TypeScript" - o que?
Yarin
a) isso é argumentum ad populum, b) todo JS IDE melhor tem conclusão ou linting de código, c) faz o google
daniel.sedlacek
Isso é pura ilusão, Sr. Sedlacek.
mystrdat
Por docs: Este sistema é chamado de Widget Factory e é exposto como jQuery.widget como parte do jQuery UI 1.8; no entanto, ele pode ser usado independentemente da interface do usuário do jQuery. Como o $ .widget é usado sem a interface do usuário do jQuery?
precisa saber é o seguinte
13

Uma abordagem mais simples é usar funções aninhadas. Em seguida, você pode encadeá-los de maneira orientada a objetos. Exemplo:

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

E aqui está como chamá-lo:

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

Tenha cuidado, porém. Você não pode chamar uma função aninhada até que ela tenha sido criada. Então você não pode fazer isso:

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

A função DoEvenMore nem existe porque a função DoSomething ainda não foi executada, o que é necessário para criar a função DoEvenMore. Para a maioria dos plugins jQuery, você realmente terá apenas um nível de funções aninhadas e não duas, como mostrei aqui.
Apenas certifique-se de que, ao criar funções aninhadas, defina essas funções no início da função pai antes que qualquer outro código na função pai seja executado.

Por fim, observe que o membro "this" é armazenado em uma variável chamada "_this". Para funções aninhadas, você deve retornar "_this" se precisar de uma referência à instância no cliente que está chamando. Você não pode simplesmente retornar "this" na função aninhada porque isso retornará uma referência à função e não à instância do jQuery. O retorno de uma referência do jQuery permite que você encadeie métodos intrínsecos do jQuery no retorno.

Polaris431
fonte
2
Isso é ótimo - eu só me pergunto por que o jQuery parece preferir chamar os métodos pelo nome, como no padrão .plugin ('method')?
W00t
6
Isso não funciona. Se você chamar o plugin em dois recipientes diferentes, as variáveis internas se substituído (nomeadamente _Isso)
mbrochh
Falha: não permite pluginContainer.MyPlugin.DoEvenMore (). DoSomething ();
Paul Swetz 26/09
9

Obtive-o do jQuery Plugin Boilerplate

Também descrito em jQuery Plugin Boilerplate, reprise

// 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
fonte
Seu método quebra o encadeamento jQuery: $('.first-input').data('pluginName').publicMethod('new value').css('color', red);retorna Cannot read property 'css' of undefined jsfiddle.net/h8v1k2pL/1 #
Alex G
@AlexG, dado este exemplo, você o adicionaria return $element; neste exemplo, você o mudaria para plugin.foo_public_method = function() {/* Your Code */ return $element;}@Salim, obrigado por me ajudar ... github.com/AndreaLombardo/BootSideMenu/pull/34
CrandellWS
6

Tarde demais, mas talvez possa ajudar alguém um dia.

Eu estava na mesma situação, criando um plug-in jQuery com alguns métodos e, depois de ler alguns artigos e alguns pneus, criei um boilerplate do plug-in jQuery ( https://github.com/acanimal/jQuery-Plugin-Boilerplate ).

Além disso, desenvolvi com ele um plug-in para gerenciar tags ( https://github.com/acanimal/tagger.js ) e escrevi dois posts explicando passo a passo a criação de um plug-in jQuery ( http: // acuriousanimal. com / blog / 2013/01/15 / coisas-eu-aprendi-criando-um-jquery-plugin-parte-i / ).

EricSonaron
fonte
possivelmente o melhor post eu vim através de ainda sobre a criação de plugins jQuery como um novato - graças;)
Dex Dave
5

Você pode fazer:

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

Dessa maneira, seu objeto de plug-ins é armazenado como valor de dados em seu elemento.

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

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

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

Que tal usar gatilhos? Alguém conhece alguma desvantagem em usá-los? O benefício é que todas as variáveis ​​internas são acessíveis através dos gatilhos, e o código é muito simples.

Veja em jsfiddle .

Exemplo 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>

Plugar

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
fonte
1
cf. seu comentário. O único problema que vejo aqui é indiscutivelmente um mau uso do sistema de eventos. É atípico usar eventos puramente para invocar uma função; parece exagero e pode ser facilmente quebrado. Normalmente, você usaria eventos de uma forma de publicação / assinatura, por exemplo, uma função publica que alguma condição "A" ocorreu. Outras entidades, interessadas em "A", ouvem a mensagem de que "A" aconteceu e depois fazem alguma coisa. Você parece usá-lo como push "comando", mas assumindo que há apenas um ouvinte. Você gostaria de ter cuidado para que sua semântica não seja quebrada pela adição de outros ouvintes.
precisa saber é o seguinte
Obrigado por seu comentário. Entendo que não é uma técnica comum e pode causar problemas se alguém adicionar acidentalmente um ouvinte de evento, mas se ele der o nome do plug-in, é muito improvável. Não conheço nenhum problema relacionado ao desempenho, mas o próprio código parece ser muito mais simples para mim do que com as outras soluções, mas posso estar perdendo alguma coisa.
István Ujj-Mészáros
3

Aqui, quero sugerir etapas para criar um plugin simples com 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>

Aqui, adicionamos o objeto padrão chamado paramse definimos os valores padrão das opções usando a extendfunção Portanto, se passarmos o argumento em branco, ele definirá os valores padrão, caso contrário, ele definirá.

Leia mais: Como criar o plugin JQuery

Gopal Joshi
fonte
Oi Gopal Joshi, Por favor, dê o próximo nível de criação de plugins jquery. esperamos da sua resposta necessária.
Sakthi Karthik
Olá @SakthiKarthik, Off cource Vou publicar um novo tutorial em breve no meu blog
Gopal Joshi
1
Oi @SakthiKarthik, Você pode consultar um novo artigo no próximo nível do plugin jquery aqui sgeek.org/…
Gopal Joshi
2

Tente 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
fonte
1

Aqui está minha versão básica disso. Semelhante aos postados antes, você chamaria como:

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

-ou acesse a instância diretamente @ 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
fonte
1

O seguinte plug-in-estrutura utiliza o jQuery- data()-Método para proporcionar uma interface pública para plug-in-métodos / -Configurações internos (preservando jQuery-chainability):

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

Agora você pode chamar métodos de plug-in internos para acessar ou modificar dados do plug-in ou o elemento relevante usando esta sintaxe:

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

Desde que você retorne o elemento atual (this) de dentro da sua implementação da myPublicPluginMethod()jQuery-chainability será preservada - portanto, o seguinte funciona:

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

Aqui estão alguns exemplos (para obter detalhes, confira este violino ):

// 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
fonte
0

Isso pode realmente ser feito para funcionar de uma maneira "agradável" usando defineProperty. Onde "nice" significa sem ter que usar ()para obter o namespace do plug-in nem passar o nome da função por string.

Nit compatibilidade: defineProperty não funciona em navegadores antigos, como o IE8 e abaixo. Advertência: $.fn.color.blue.apply(foo, args) não vai funcionar, você precisa usar 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();

Link JSFiddle

kralyk
fonte
0

De acordo com o padrão jquery, você pode criar um plugin da seguinte forma:

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

Como chamar este plugin?

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

Referência: link

Mahesh
fonte
0

Eu acho que isso pode ajudá-lo ...

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

No exemplo acima, eu criei um plugin simples de destaque do jquery. Eu havia compartilhado um artigo no qual discuti sobre Como criar seu próprio plugin do jQuery, do básico ao avançado. Eu acho que você deveria dar uma olhada ... http://mycodingtricks.com/jquery/how-to-create-your-own-jquery-plugin/

Shubham Kumar
fonte
0

A seguir, um pequeno plug-in para ter um método de aviso para fins de depuração. Mantenha esse código no arquivo 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
fonte
0

Aqui está como eu faço isso:

(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
fonte
-2

O que você fez é basicamente estender o objeto jQuery.fn.messagePlugin pelo novo método. O que é útil, mas não no seu caso.

Você tem que fazer é 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);
  });

};

Mas você pode realizar o que deseja, quero dizer que existe uma maneira de fazer $ ("# mydiv"). MessagePlugin (). SaySomething ("olá"); Meu amigo, ele começou a escrever sobre lugins e como estendê-los com sua cadeia de funcionalidades, aqui está o link para o blog dele

James
fonte