天天看點

jQuery插件開發 - 翻譯自官網

1,開始

可以通過為jQuery.fn增加一個新的函數來編寫jQuery插件。屬性的名字就是你的插件的名字:

jQuery.fn.myPlugin = function(){
    //開始寫你的代碼吧!
};      

 但是,那惹人喜愛的美元符号$哪裡去了?她就是jQuery,但是為了確定你的插件與其他使用$的庫不沖突,最好使用一個立即執行的匿名函數,這個匿名函數的參數是jQuery,這樣其他的庫就可以放心的使用$符号了。

(function( $ ){
  $.fn.myPlugin = function() {
  
    // 開始吧!

  };
})( jQuery );      

 這樣更好了就。在閉包内,可以放心的使用$符号了~

2,上下文

現在已經可以編寫我們的代碼了,但是編寫之前,我必須說一說上下文。在插件内部的範圍中,this關鍵字指向的是jQuery對象。人們很容易誤解這一點,因為在正常使用jQuery的時候,this通常指向的是一個DOM元素。不了解這一點,會經常使用$又包裝了一次。

(function( $ ){

  $.fn.myPlugin = function() {
  
    // 沒有必要使用$(this)

    // $(this) 跟 $($('#element'))是一樣的
        
    this.fadeIn('normal', function(){

      //這裡的this指的就是一個DOM元素了

    });

  };
})( jQuery );

$('#element').myPlugin();      

3,基本開發 

接下來寫一個能用的插件吧。

(function( $ ){

  $.fn.maxHeight = function() {
  
    var max = 0;

    this.each(function() {
      max = Math.max( max, $(this).height() );
    });

    return max;
  };
})( jQuery );      
var tallest = $('div').maxHeight();      

 這是一個簡單的插件,通過調用height()傳回頁面上height最大的div的height。

4,維護鍊式開發的特性

上一個例子是傳回了一個整數,但是大多數情況下,一個插件緊緊是修改收集到的元素,然後傳回這個元素讓鍊條上的下一個使用。這是jQuery設計的精美之處,也是jQuery如此流行的原因之一。為了保證可鍊式,你必須傳回this。

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

 因為該插件傳回了this,是以保證了可鍊式,進而可以繼續使用jQuery方法進行修改,如css()。如果你的插件如果不是傳回一個簡單值,你通常應該傳回this。而且,正如你可能想到的,你傳進去的參數也可以在你的插件中通路。是以在這個例子中,可以通路到type。

5,預設值和選項

為了一些複雜的,可訂制的插件,最好提供一套預設值,在被調用的時候擴充預設值。這樣,調用函數的時候就不用傳入一大堆參數,而是傳入需要被替換的參數。你可以這樣做:

(function( $ ){

  $.fn.tooltip = function( options ) {  

    var settings = {
      'location'         : 'top',
      'background-color' : 'blue'
    };

    return this.each(function() {        
      // 如果存在選項,則合并之
      if ( options ) { 
        $.extend( settings, options );
      }

      // 其他代碼咯

    });

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

 在這個例子中,調用插件後,預設的location會被替換城'left',而background-color還是'blue'。這樣可以保證高度可配置性,而不需要開發者定義所有可能的選項了。

6,命名空間

正确的命名空間對于插件開發十分重要,這樣能確定你的插件不被其他插件重寫,也能避免被頁面上其他代碼重寫。命名空間可以使你更長壽,因為你能記錄你自己的方法,事件,資料等。

a,插件方法

在任何情況下,都不要在一個插件中為jQuery.fn增加多個方法。如:

(function( $ ){

  $.fn.tooltip = function( options ) { // 這樣 };
  $.fn.tooltipShow = function( ) { // 是   };
  $.fn.tooltipHide = function( ) { // 不好的  };
  $.fn.tooltipUpdate = function( content ) { // 同學!  };

})( jQuery );      

 不推薦這樣使用,搞亂了$.fn命名空間。要糾正之,你可以把所有的方法放進一個對象中,然後通過不同的參數來調用。

(function( $ ){

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

  $.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' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    
  
  };

})( jQuery );      
$('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      

jQuery自己的擴充也是使用這種插件結構。

b,事件

綁定事件的命名空間是比較不為人知的。如果你的插件綁定了某個事件,最好将它搞到一個命名空間中。這樣,如果你以後需要解綁,就不會影響到其他綁定到這個事件上的函數了。你可以使用".<namespace>"來增加命名空間。

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

在這個例子中,tooltip在init方法中初始化,它将reposition方法綁定到window對象的resize事件的tooltip名字空間下。稍候,如果開發者需要去掉這個tooltip,我們可以解綁這個綁定。這樣就不會影響到其他綁定到window對象的resize事件的方法了。

c,資料

在開發插件的時候,你通常會有保持狀态或者檢查你的插件是否已經初始化的需要。使用jQuery的data方法是保持變量的很好的方法。但是,我們不把變量單獨儲存,而是放在一個對象中,這樣就可以在一個名字空間下統一通路了。

(function( $ ){

  var methods = {
     init : function( options ) {

       return this.each(function(){
         
         var $this = $(this),
             data = $this.data('tooltip'),
             tooltip = $('<div />', {
               text : $this.attr('title')
             });
         
         // If the plugin hasn't been initialized yet
         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 );      

 使用data方法可以幫助你在插件的各個方法間保持變量和狀态。将各種變量放在一個對象中,可以友善通路,也可以友善移除。

7,總結與最佳實踐

編寫jQuery插件可以充分利用庫,将公用的函數抽象出來,“循環利用”。以下是簡短的總結:

  • 使用(function($){//plugin})(jQuery);來包裝你的插件
  • 不要在插件的初始範圍中重複包裹
  • 除非你傳回原始值,否則傳回this指針來保證可鍊式
  • 不要用一串參數,而是使用一個對象,并且設定預設值
  • 一個插件,不要為jQuery.fn附上多個函數
  • 為你的函數,事件,資料附着到某個命名空間