Plugins - Authoring
Autor: Osvaldo Bodo | Publicado: 2011-11-16T19:52:00-02:00











Texto Extraido e traduzido do Original site Jquery 


Então você se sentir confortável com jQuery e gostaria de aprender a escrever seus próprios plugins. Grande Você está no lugar certo. Estendendo jQuery com plugins e métodos é muito poderoso e pode salvar você e seus colegas de muito tempo de desenvolvimento abstraindo as suas funções mais inteligentes para plugins. Este post irá delinear o básico, melhores práticas e as armadilhas comuns que atente para que você começar a escrever seu plugin.




Conteúdo


1 Introdução
2 contexto
3 O Básico
4 Manter a capacidade da cadeia
5 Defaults e Opções
6 espaçamento nome 
6.1 Plugin Metodo
6.2 Eventos
6.3 Dados


7 Práticas Resumo e Melhor


[edit]


Introdução
Para escrever um plugin jQuery, começar adicionando uma propriedade nova função para o objeto jQuery.fn onde o nome da propriedade é o nome do seu plugin:


jQuery.fn.myPlugin = function() {

  // Do your awesome plugin stuff here

};

Mas espere! Onde está o meu sinal de dólar incrível que eu conheço e amo? Ele ainda está lá, no entanto para ter certeza que seu plugin não colida com outras bibliotecas que possam usar o cifrão, é uma boa prática para passar jQuery para uma função auto-executório (fechamento), que mapeia para o sinal de dólar para que ele possa 't ser substituído por outra biblioteca no âmbito da sua execução.

(function( $ ) {
  $.fn.myPlugin = function() {
  
    // Do your awesome plugin stuff here

  };
})( jQuery );

Ah, isso é melhor. Agora dentro desse fechamento, podemos usar o cifrão no lugar do jQuery, tanto quanto nós gostamos.

[edit]


Contexto 
Agora que temos o nosso shell nós podemos começar a escrever o nosso código dos plugins propriamente dita. Mas antes de fazer isso, eu gostaria de dizer uma palavra sobre o contexto. No âmbito imediato da função de plugin, a palavra-chave refere-se ao objeto jQuery o plugin foi chamado em. Este é um deslizamento comum até devido ao fato de que, em outros casos em que jQuery aceita um callback, a esta palavra-chave se refere ao elemento DOM nativa. Isso muitas vezes leva a desenvolvedores desnecessariamente envolvendo a palavra-chave this (de novo) na função jQuery.

(function( $ ){

  $.fn.myPlugin = function() {
  
    // there's no need to do $(this) because
    // "this" is already a jquery object

    // $(this) would be the same as $($('#element'));
        
    this.fadeIn('normal', function(){

      // the this keyword is a DOM element

    });

  };
})( jQuery );



$('#element').myPlugin();  // esta é a chamada &nbsp;

&nbsp;


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(); // Returns the height of the tallest div




















Este é um plugin simples que utiliza .Height () para retornar a altura dos mais altos div na página.















Maintaining Chainability&nbsp;
The previous example returns an integer value of the tallest div on  the page, but often times the intent of a plugin is simply modify the  collection of elements in some way, and pass them along to the next  method in the chain. This is the beauty of jQuery's design and is one of  the reasons jQuery is so popular. So to maintain chainability in a  plugin, you must make sure your plugin returns the this keyword. 
(function( $ ){

  $.fn.lockDimensions = function( type ) {  

    return this.each(function() {

      var $this = $(this);

      if (&nbsp;!type || type == 'width' ) {
        $this.width( $this.width() );
      }

      if (&nbsp;!type || type == 'height' ) {
        $this.height( $this.height() );
      }

    });

  };
})( jQuery );

$('div').lockDimensions('width').css('color', 'red');

Because the plugin returns the this keyword in its  immediate scope, it maintains chainability and the jQuery collection can  continue to be manipulated by jQuery methods, such as .css. So if your plugin doesn't return an intrinsic value, you should always return the this  keyword in the immediate scope of the plugin function. Also, as you  might assume, arguments you pass in your plugin invocation get passed to  the immediate scope of the plugin function. So in the previous example,  the string 'width' becomes the type argument for the plugin function. 

[edit]


 Defaults and Options 
For more complex and customizable plugins that provide many options,  it's a best practice to have default settings that can get extended  (using $.extend)  when the plugin is invoked. So instead of calling a plugin with a large  number of arguments, you can call it with one argument which is an  object literal of the settings you would like to override. Here's how  you do it. 
(function( $ ){

  $.fn.tooltip = function( options ) {  

    // Create some defaults, extending them with any options that were provided
    var settings = $.extend( {
      'location'        &nbsp;: 'top',
      'background-color'&nbsp;: 'blue'
    }, options);

    return this.each(function() {        

      // Tooltip plugin code here

    });

  };
})( jQuery );

$('div').tooltip({
  'location'&nbsp;: 'left'
});

In this example, after calling the tooltip plugin with the given  options, the default location setting gets overridden to become 'left', while the background-color setting remains the default 'blue'. So the final settings object ends up looking like this: 
{
  'location'        &nbsp;: 'left',
  'background-color'&nbsp;: 'blue'
}

This is a great way to offer a highly configurable plugin without requiring the developer to define all available options. 

[edit]


 Namespacing 
Properly namespacing your plugin is a very important part of plugin  development. Namespacing correctly assures that your plugin will have a  very low chance of being overwritten by other plugins or code living on  the same page. Namespacing also makes your life easier as a plugin  developer because it helps you keep better track of your methods, events  and data. 

[edit]


 Plugin Methods 
Under no circumstance should a single plugin ever claim more than one namespace in the jQuery.fn object. 
(function( $ ){

  $.fn.tooltip = function( options ) { 
    // THIS
  };
  $.fn.tooltipShow = function( ) {
    // IS
  };
  $.fn.tooltipHide = function( ) { 
    // BAD
  };
  $.fn.tooltipUpdate = function( content ) { 
    //&nbsp;!!!  
  };

})( jQuery );

This is a discouraged because it clutters up the $.fn  namespace. To remedy this, you should collect all of your plugin's  methods in an object literal and call them by passing the string name of  the method to the plugin. 
(function( $ ){

  var methods = {
    init&nbsp;: function( options ) { 
      // THIS 
    },
    show&nbsp;: function( ) {
      // IS
    },
    hide&nbsp;: function( ) { 
      // GOOD
    },
    update&nbsp;: function( content ) { 
      //&nbsp;!!! 
    }
  };

  $.fn.tooltip = function( method ) {
    
    // Method calling logic
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' ||&nbsp;! 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&nbsp;: 'bar'
});

// calls the hide method
$('div').tooltip('hide'); 

// calls the update method
$('div').tooltip('update', 'This is the new tooltip content!'); 

This type of plugin architecture allows you to encapsulate all of  your methods in the plugin's parent closure, and call them by first  passing the string name of the method, and then passing any additional  parameters you might need for that method. This type of method  encapsulation and architecture is a standard in the jQuery plugin  community and it used by countless plugins, including the plugins and  widgets in jQueryUI. 

[edit]


 Events 
A lesser known feature of the bind  method is that is allows for namespacing of bound events. If your  plugin binds an event, its a good practice to namespace it. This way, if  you need to unbind  it later, you can do so without interfering with other events that  might have been bound to the same type of event. You can namespace your  events by appending “.” to the type of event you're  binding. 
(function( $ ){

  var methods = {
     init&nbsp;: function( options ) {

       return this.each(function(){
         $(window).bind('resize.tooltip', methods.reposition);
       });

     },
     destroy&nbsp;: function( ) {

       return this.each(function(){
         $(window).unbind('.tooltip');
       })

     },
     reposition&nbsp;: function( ) { 
       // ... 
     },
     show&nbsp;: function( ) { 
       // ... 
     },
     hide&nbsp;: function( ) {
       // ... 
     },
     update&nbsp;: 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' ||&nbsp;! 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');

In this example, when the tooltip is initialized with the init  method, it binds the reposition method to the resize event of the window  under the namespace 'tooltip'. Later, if the developer needs to destroy  the tooltip, we can unbind the events bound by the plugin by passing  its namespace, in this case 'tooltip', to the unbind method. This allows  us to safely unbind plugin events without accidentally unbinding events  that may have been bound outside of the plugin. 

[edit]


 Data 
Often times in plugin development, you may need to maintain state or  check if your plugin has already been initialized on a given element.  Using jQuery's data  method is a great way to keep track of variables on a per element  basis. However, rather than keeping track of a bunch of separate data  calls with different names, it's best to use a single object literal to  house all of your variables, and access that object by a single data  namespace.  
(function( $ ){

  var methods = {
     init&nbsp;: function( options ) {

       return this.each(function(){
         
         var $this = $(this),
             data = $this.data('tooltip'),
             tooltip = $('
', {
               text&nbsp;: $this.attr('title')
             });
         
         // If the plugin hasn't been initialized yet
         if (&nbsp;! data ) {
         
           /*
             Do more setup stuff here
           */

           $(this).data('tooltip', {
               target&nbsp;: $this,
               tooltip&nbsp;: tooltip
           });

         }
       });
     },
     destroy&nbsp;: function( ) {

       return this.each(function(){

         var $this = $(this),
             data = $this.data('tooltip');

         // Namespacing FTW
         $(window).unbind('.tooltip');
         data.tooltip.remove();
         $this.removeData('tooltip');

       })

     },
     reposition&nbsp;: function( ) { // ... },
     show&nbsp;: function( ) { // ... },
     hide&nbsp;: function( ) { // ... },
     update&nbsp;: 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' ||&nbsp;! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    
  
  };

})( jQuery );


Using data helps you keep track of variables and state across method  calls from your plugin. Namespacing your data into one object literal  makes it easy to access all of your plugin's properties from one central  location, as well as reducing the data namespace which allows for easy  removal if need be. 

[edit]


 Summary and Best Practices
Writing jQuery plugins allows you to make the most out of the library  and abstract your most clever and useful functions out into reusable  code that can save you time and make your development even more  efficient. Here's a brief summary of the post and what to keep in mind  when developing your next jQuery plugin: 

 Always wrap your plugin in a closure: (function( $ ){ /* plugin goes here */ })( jQuery ); 
 Don't redundantly wrap the this keyword in the immediate scope of your plugin's function 
 Unless you're returning an intrinsic value from your plugin, always have your plugin's function return the this keyword to maintain chainability. 
 Rather than requiring a lengthy amount of arguments, pass your  plugin settings in an object literal that can be extended over the  plugin's defaults. 
 Don't clutter the jQuery.fn object with more than one namespace per plugin. 
 Always namespace your methods, events and data. 
 jQuery.fn is pronounced jQuery effin' 


&nbsp;