Primeiros passos
Para escrever um plugin jQuery, comece adicionando uma nova função para o objeto jQuery.fn onde o nome da função é o nome do seu plugin:
jQuery.fn.myPlugin = function() { // Faça o seu plugin de coisas incríveis aqui };
Mas espere! Onde está o meu sinal de cifrão incrível que eu conheço e amo? Ele ainda está lá, no entanto, a certeza de que o seu plugin não colidir com outras bibliotecas que podem usar o sinal de $, é a melhor prática para passar jQuery para um IIFE (Immediately Invoked Function Expression) que mapeia para o sinal de $, por isso, não pode ser substituído por outra biblioteca no momento da sua execução.
(function( $ ) { $.fn.myPlugin = function() { // Faça o seu plugin de coisas incríveis aqui }; })( jQuery );
Ah, isso é melhor. Agora, dentro desse encerramento, podemos usar o cifrão no lugar do jQuery, tanto quanto nós gostamos.
Contexto
Agora que temos o nosso escudo, podemos começar a escrever o nosso código do plugin atual. Mas antes de fazer isso, eu gostaria de dizer uma palavra sobre o contexto: No momento imediato da função de plugin, a this palavra-chave se refere ao objeto jQuery o plugin. Este é um deslizamento comum se deve ao fato de que, em outros casos em que jQuery aceita uma chamada de retorno, a this palavra-chave se refere ao elemento DOM natural. Isso muitas vezes leva a desenvolvedores desnecessariamente embalar a this palavra-chave (de novo) na função jQuery.
(function( $ ){ $.fn.myPlugin = function() { // não há necessidade de fazer $ (this) porque // "this" já é um objeto jquery //$ (this) seria o mesmo que $ ($ ('# elemento')); this.fadeIn('normal', function(){ //a palavra-chave é um elemento DOM }); }; })( jQuery );
$('#element').myPlugin();;
O Básico
Agora que entendemos o contexto de plugins jQuery, vamos escrever um plugin que realmente faz alguma coisa.
(function( $ ){ $.fn.maxHeight = function() { var max = 0; this.each(function() { max = Math.max( max, $(this).height() ); }); return max; }; })( jQuery );
var tallest = $('div').maxHeight(); // Retorna a altura da mais alta div
Este é um plugin simples que aproveita .height() para retornar a altura da mais alta div na página.
Manter Preso
O exemplo anterior retorna um valor inteiro da mais alta div na página, mas muitas vezes a intenção de um plugin é simplesmente modificar a coleção de elementos, de alguma forma, e passá-las para o próximo método da cadeia. Esta é a beleza do design do jQuery e é uma das razões do jQuery ser tão popular. Assim, para manter preso o plugin, você deve se certificar de seu plugin retorna a this palavra-chave.
(function( $ ){ $.fn.lockDimensions = function( type ) { return this.each(function() { var $this = $(this); if ( !type || type == 'width' ) { $this.width( $this.width() ); } if ( !type || type == 'height' ) { $this.height( $this.height() ); } }); }; })( jQuery );
$('div').lockDimensions('width').css('color', 'red');
O plugin retorna a this palavra-chave em seu alvo imediato, mantendo preso e a coleção jQuery podem continuar a ser manipulado por métodos jQuery, como .css . Então, se o seu plugin não retornar um valor próprio, você deve sempre retornar a this palavra-chave no momento imediato da função de plugin. Além disso, como se poderia supor, argumentos que você passa em sua janela plugin passam para o alcance imediato da função de plugin. Assim, no exemplo anterior, “width” a string torna-se o tipo de argumento para a função de plugin.
Padrões e Opções
Para plugins mais complexos e personalizavéis que oferecem muitas opções, é uma boa prática para ter configurações padrão que pode se estendido (usando $.extend ). Então, ao invés de chamar um plugin com um grande número de argumentos, você pode chamá-lo com um argumento que é um objeto literal das configurações que você gostaria de substituir. Aqui está como fazê-lo.
(function( $ ){ $.fn.tooltip = function( options ) { // Criar alguns padrões, estendendo-os com todas as opções que foram fornecidos var settings = $.extend( { 'location' : 'top', 'background-color' : 'blue' }, options); return this.each(function() { // Dica código plugin aqui }); }; })( jQuery );
$('div').tooltip({ 'location' : 'left' });
Neste exemplo, depois de chamar o plugin dica com as opções dadas, a definição de local padrão fica substituída para se tornar ‘left’, enquanto a configuração de cor de fundo continua a ser o padrão ‘blue’. Assim, o objeto de definições finais acaba parecido com isto:
{ 'location' : 'left', 'background-color' : 'blue' }
Esta é uma ótima maneira de oferecer um plugin altamente configurável sem que o desenvolvedor defina todas as opções disponíveis.
Namespacing
Devidamente namespacing é uma parte muito importante de desenvolvimento de plugins. Namespacing corretamente assegura que seu plugin terá uma chance muito baixa de ser substituído por outros plugins ou códigos na mesma página. Namespacing também facilita a sua vida como um desenvolvedor de plug-in porque ajuda a manter um melhor controle de seus métodos, eventos e dados.
Métodos Plugin
Sob nenhuma circunstância deve um único plugin sempre reivindicar mais do que um espaço para nome no jQuery.fn objeto.
(function( $ ){ $.fn.tooltip = function( options ) { // Isso }; $.fn.tooltipShow = function( ) { // eh }; $.fn.tooltipHide = function( ) { // mal }; $.fn.tooltipUpdate = function( content ) { // !!! }; })( jQuery );
Isto dá uma desanimada porque tumultua o $.fn namespace. Para corrigir isso, você deve coletar todos os métodos de seu plugin em um objeto literal e chamá-los, passando o método para o plugin.
(function( $ ){ var methods = { init : function( options ) { // isso }, show : function( ) { // eh }, hide : function( ) { // bom }, update : function( content ) { // !!! } }; $.fn.tooltip = function( method ) { // Metódo de chamada 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 exist on jQuery.tooltip' ); } }; })( jQuery ); // calls the init method $('div').tooltip(); // calls the init method $('div').tooltip({ foo : 'bar' });
$('div').tooltip('hide');
$('div').tooltip('update', 'This is the new tooltip content!');
Esse tipo de arquitetura plugin permite que você apressionem todos os seus métodos no fechamento do plugin pai, e chame-os primeiro passando o nome de string do método. E então passando quaisquer parâmetros adicionais que você pode precisar para esse método. Este tipo de método e arquitetura é um padrão na comunidade plugin jQuery e utilizado por inúmeros plugins, incluindo os plugins e widgets em jQueryUI .
Eventos
Uma característica menos conhecida do ligamento método é que é permite namespacing de eventos ligados. Se o seu plugin se liga um evento, sua prática um bom espaço para isso. Dessa forma, se você precisa desvincular -lo mais tarde, você pode fazer isso sem interferir com outros eventos que poderiam ter sido vinculados ao mesmo tipo de evento. Você pode namespace seus eventos anexando “.
(function( $ ){ var methods = { init : function( options ) { return this.each(function(){ $(window).bind('resize.tooltip', methods.reposition); }); }, destroy : function( ) { return this.each(function(){ $(window).unbind('.tooltip'); }) }, reposition : function( ) { // ... }, show : function( ) { // ... }, hide : function( ) { // ... }, update : function( content ) { // ... } }; $.fn.tooltip = function( 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 exist on jQuery.tooltip' ); } }; })( jQuery );
$('#fun').tooltip(); // Some time later... $('#fun').tooltip('destroy');
Neste exemplo, quando a dica é inicializada com o método init, liga-se a reposição de método para o evento de redimensionamento da janela, em ‘dica’ do namespace. Mais tarde, se o desenvolvedor precisar apagar a dica de ferramenta, podemos desvincular os eventos vinculados pelo plugin passando seu namespace, em ‘dica’. Neste caso, o método unbind. Isso nos permite com segurança desvincular eventos do plugin sem eventos acidentalmente vinculantes que podem ter sido ligadas fora do plugin.
Dados
Muitas vezes no desenvolvimento de plug-in, você pode precisar manter o estado ou verificar se o seu plugin já foi inicializado em um determinado elemento. Usando jQuery dados é uma ótima maneira de manter o controle de variáveis em uma base por elemento. No entanto, ao invés de manter o controle de um grupo de chamadas de dados separados com nomes diferentes, o melhor é usar um único objeto literal para abrigar todas as suas variáveis, e acessar o objeto por um namespace de dados único.
(function( $ ){ var methods = { init : function( options ) { return this.each(function(){ var $this = $(this), data = $this.data('tooltip'), tooltip = $('', { text : $this.attr('title') }); // Se o plugin não foi inicializado ainda if ( ! data ) { /* Do more setup stuff here */ $(this).data('tooltip', { target : $this, tooltip : tooltip }); } }); }, destroy : function( ) { return this.each(function(){ var $this = $(this), data = $this.data('tooltip'); // Namespacing FTW $(window).unbind('.tooltip'); data.tooltip.remove(); $this.removeData('tooltip'); }) }, reposition : function( ) { // ... }, show : function( ) { // ... }, hide : function( ) { // ... }, update : function( content ) { // ...} }; $.fn.tooltip = function( 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 exist on jQuery.tooltip' ); } }; })( jQuery );
Usar os dados ajuda você a manter o controle das variáveis e do estado em todas as chamadas de método de seu plugin. Namespacing seus dados em um objeto literal torna fácil acessar todas as propriedades do seu plugin de um local central bem como a redução do espaço de dados que permite a fácil remoção se necessário.
Resumo Práticas e Melhor
Escrevendo plugins jQuery permite que você faça o máximo proveito da biblioteca e abstratos suas funções mais inteligentes e úteis para fora no código reutilizável que você pode economizar tempo e fazer o seu desenvolvimento ainda mais eficiente. Aqui está um breve resumo do post para manter na mente do desenvolvidor de plugin jQuery:
- Sempre envolver o seu plugin em um fechamento:
(function( $ ){ /* plugin goes here */ })( jQuery );
Não envolver o this palavra-chave no momento imediato da função de seu plugin.A menos que você esteja retornando um valor próprio do plugin, sempre retorne seu plugin a função this palavra-chave para manter chainability.
Em vez de exigir um longo período de argumentos, passe as configurações de seu plugin para um objeto literal que pode ser estendido sobre padrões do plugin.
Não desorganizar o jQuery.fn objeto com mais de um namespace por plugin.
Sempre namespace seus métodos, eventos e dados.