Um padrão de desenvolvimento para plugins do jQuery

Originalmente escrito por Mike Alsup no blog Learning jQuery

Eu tenho desenvolvido plugins do jQuery por um tempo e me acostumei com um estilo bastante particular de desenvolver plugins para meus scripts. Este artigo pretende compartilhar o padrão de desenvolvimento que eu achei extremamente útil para a autoria de plugins. Ela parte do pressuposto que você já tenha conhecimento do desenvolvimento de plugins para jQuery. Se você um autor de plugin novato, por favor leia o Guia de autoria de plugins do jQuery (inglês, por enquanto ;-) )

Há poucos requerimentos que eu acho fazer um plugin se comportar bem:

  • Dê somente um nome no namespace do jQuery
  • Aceite um argumento de opções para controlar o comportamento do plugin
  • Provê acesso público para configurações de plugin padrões
  • Provê acesso público para funções secundárias (quando possível)
  • Mantenha funções privadas privadas

Eu analisei esses requerimentos um a um, e trabalhei em cima dele para construir um simples plugin que pisca o texto.

Dando um único nome no namespace do jQuery

Isto implica o único script para cada plugin. Se seu script contém múltiplos plugins, ou complementa outros plugins (como $.fn.facaAlgo() e $.fn.desfacaAlgo() ) então múltiplos nomes são necessários. Mas em geral quando estamos desenvolvendo um plugin, tente ao máximo usa somente um único nome para conter todos os detalhes da implementação.

No nosso plugin de exemplo nós iremos colocar o nome “hilight” .

//definicao do plugin

$.fn.hilight = function(){

//a implementacao do plugin vem aqui};

// executando o plugin em outro script

$("#myDiv").hilight();

Mas e se quebrarmos nossa implementação em mais de uma função? Há muitas razões para se fazer isto: o design pode requerer isto que pode resultar em uma implementação mais simples e mais versátil; e irá manipular melhor as semânticas da programação orientada a objeto.

É realmente trivial quebrar a implementação em múltiplas funções sem adicionar “sujeira” no namespace. Nós iremos fazer isto reconhecendo, e levando vantagem do fato de funções no javascript serem objetos da primeira classe. Como qualquer outro objeto, funções podem conter propriedades. Desde que nós já demos um nome para o “hilight” no objeto jQuery prototype, qualquer outra propriedade ou função que nós precisamos expor pode ser declarada como propriedade da função “hilight”. Mais sobre isto adiante.

Adicionar o argumento de opções para controlar o comportamento do plugin

Vamos adicionar suporte para nosso plugin hilight para especificar a cor de frente e de fundo para serem usadas. Nós deveremos permitir opções como estas passadas como um argumento de opções para a função do plugin. Por exemplo:

//definicao do plugin$.fn.hilight = function(options) {

var defaults = {

foreground: 'red';

background: 'yellow';

};};

//extendendo nossas opcoes

var opts = $.extend(defaults,options);

//implementacao do plugin

//seu plugin pode ser invocado assim:

$('#myDiv').hilight({

foreground: 'blue'

});

Provê acesso público para configurações padrões do plugin

Um aparfeiçoamento que podemos ter, e deveríamos, é fazer o código acima “expor” as configurações padrões do plugin. Isto é importante por que torna-se muito fácil para os usuários sobrescreverem / customizarem o plugin com código mínimo. E é assim que começaremos a tirar vantagem do objeto função.

//definicao do plugin

$.fn.hilight = function(options) {

//extendendo nossa opcao padrao

//note que o primeiro argumento

// e um objeto vazio, isto e para

// mante-lo de nao alterar o "defaults"

var opts = $.extend({},$.fn.hilight.defaults,options);

// implementacao do plugin vem aqui

};

//padrao do plugin$.fn.hilight.defaults = {

foreground: 'red';

background: 'yellow';

};//Agora usuários podem incluir

//uma linha como esta nos seus scripts

$.fn.hilight.defaults.foreground = 'blue';

//agora poderemos chamar o metodo

//do plugin e ele ficara com uma cor

// de frente azul por padrao

$('#myDiv').hightlight();

Como podemos ver, nós permitimos o usuário a escrever uma única linha de código para alterar a propriedade padrão da cor de frente para o plugin. E os usuários podem seletivamente sobrescrever este novo método padrão quando desejamos:

//sobrescrever a cor de frente padrao

$.fn.hilight.defaults.foreground = 'blue';

//invocando o plugin usando o padrao
$('.hilightDiv').hiligth();
//sobrescrevendo passando um options

$("#green").hiligth({

foreground: 'green';

});

Provê acesso público para acessar funções secundárias quando aplicável

Este item vai de mãos dadas com o item anterior e é uma maneira interessante de extender seu plugin (e para deixar outros estenderem seu plugin). Por exemplo, a implementação de seu plugin pode definir uma função chamada “format” que formata o texto com hilight. Nosso plugin pode agora se parecer assim, com a implementação padrão do método format definido abaixo da função hilight.

//definicao do plugin

$.fn.hilight = function(options) {

//percorrer e reformatar cada elemento encontrado
return this.each(function() {

var $this = $(this);

var markup = $this.html();

// call our format function

markup = $.fn.hilight.format(markup);

$this.html(markup);

});

};

//definir a funcao format

$.fn.hilight.format = function(txt) {

return '' + txt + '';

};

Nós poderíamos facilmente suportar outra propriedade no options object que permite uma função de callback para sobrescrever a formatação padrão. Isto é outro suporte excelente para customização de plugins. A técnica mostrada aqui vai um passo mais adiante expondo a função format para ser redefinida. Com esta técnica seria possível para outros fazerem seus próprios “sobrescrevidos” personalizados de seus plugins, eu outras palavras, significa que outros possam escrever plugins de seus plugins.
Considerando o exemplo trivial de plugin construído neste artigo, você pode estar se perguntando como isto deveria ser útil. Um exemplo do mundo real é o Cycle plugin. O Cycle plugin é um slideshow que suporta um número de bibliotecas implementadas como efeito de scroll, slide, fade, etc. Mas realisticamente, não há maneira de de definir cada único tipo de efeito que você gostaria de aplicar a uma transição slide. E que onde este tipo de versatilidade é útil. O Cycle Plugin expõe o objeto “transition” que permite usuários adicionem suas próprias transições customizadas.

$.fn.cycle.transitions = {

//implementacao aqui

}

Com esta técnica, torna-se possível para outros definirem e darem definições de transição “plugados” ao Cycle Plugin.

Manterem funções privadas, privadas!

A técnica de expor parte de seu plugin para serem sobrescritas podem ser muito poderosas. Mas se você precisa pensar cuidadosamente sobre que partes de sua implementação você deixaria exposto. Uma vez exposto, você precisa manter em mente que qualquer mudanças para os argumentos chamados ou semântica pode quebrar problemas de compatibilidade. Como regra geral, se você não tem certeza que função particular expor, você provavelmente não deveria.

Então como definir mais funções sem estragar o namespace e sem expor a implementação? Isto é uma tarefa para os “closures“. Para demonstrar, vamos adicionar outra função para nosso plugin chamada “debug”. A função debug irá logar o número de elementos selecionados para o console do firebug. Para criar um “closure“, nós escrevemos o plugin inteiro dentro de uma função.

(function($) {

$.fn.hilight = function(options){

debug(this);

}

};

//funcao privada para debugar

function debug($obj) {

if(window.console && window.console.log)

window.console.log('hilight selection count:' + $obj.size());

};

//fim do closure

})(jQuery);

Nosso método “debug” não pode ser acessado fora do “closure” e isto será uma implementação para o jQuery de métodos privados.

Este padrão de desenvolvimento tem permitido fazer que criemos mais poderosos e consistentes plugins. Eu espero que isto ajude a você fazer o mesmo.

Deixe uma resposta

O seu endereço de email não será publicado Campos obrigatórios são marcados *

*

Você pode usar estas tags e atributos de HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>