由於網頁設計目前用到jQuery的機率越來越高,常常寫了一段程式碼需要重複使用,於是決定把它製作成模組使用
建立一個Plugin
(function($){ $.fn.helloworld = function(){ alert('Hello World'); } })(jQuery);
照jQuery文件說明,是可以這樣寫
jQuery.fn.helloworld = function(){ alert('Hello World'); }
不過一方面為了方便使用「$」字號,且不與其他函式庫衝突,所以就使用外層包著,這樣就可以在裡面使用「$」字號,不會衝突。
this代表的意義
假設我們這麼寫了一段程式碼
(function($){ $.fn.showbox = function(){ this.fadeIn('slow'); } })(jQuery);
然後我們只要這樣使用
$('div').showbox();
div就會依照Plugin內的程式碼去執行,this就等於div這個物件,不需再另外再去指定。
保持鏈結(Maintaing Chainability)
下面有個範例<取自jQuery網站>
(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');
照上面的範例,因為這個物件必須接著下面繼續的動作,所以在lockDimensions這個plugin必須回傳this,才能繼續接著.css()這類其他jQuery的函式,要是沒有回傳this的話,就會接不到物件,而後面動作都沒有效果。
設定預設值和選項(Defaults and Options)
許多功能性較複雜的plugin,會給予使用者很多選項去選擇所需的功能,來符合自己的需求,而這些選項必然需要預設值來確保plugin的運作正常,當使用者忘記給予一些參數時,預設值能自動替補上去,來讓程式運行正常。
(function( $ ){ $.fn.box = function( options ) { //設定選項和預設值 var settings = $.extend( { 'width' : '200px', 'height' : '200px', 'background-color' : 'blue' }, options); return this.each(function() { alert(settings.width); }); }; })( jQuery );
$("div").box(); //200px $("div").box( { 'width': 300px } }; //300px
在沒有給予選項狀態下,plugin預設會使用程式碼編寫時的預設值。
預設值是一個非常重要的東西,常常再編寫程式碼時忘記給予參數造成程式掛點,如果有設定預設值,就算忘記給予參數,也可以讓程式順利執行。
命名(Namespacing)
這段是jQuery文件中提到的,我也非常認同好的且正確的命名plugin是應該做的事情,其實這也不也僅限於jQuery Plugin而已,在任何程式碼中正確的命名都是必須的,最好用幫自己小孩取名子的心態下去取,總不會把自己的小孩叫a,b,c這類的名稱吧,文件中提到正確的命名可以將名稱衝突的機率降到最低,避免太多隻plugin一起引入時,因為不好的命名結果造成覆蓋,程式無法正確執行,另一方面,正確的命名可以方便開發者快速的追蹤問題,這是非常重要的,畢竟時間就是金錢,因為今天自己的命名不小心結果造成要花更大的成本去檢查錯誤,最後發現命名衝突,這該有多嘔。
多種方法(Plugin Methods)
有的時候我們在寫一隻plugin,會有許多方法可以讓使用者可以選擇,但是每種方法都寫一隻plugin又太多餘,且難以維護管理,且互相都有相依性,這時候就可以這樣寫。
(function($){ var methods = { init : function( options ) { var settings = $.extend({ 'width': '200px' },options); this.css('width', settings.width); }, show : function( ) { this.show(); }, hide : function( ) { this.hide(); }, spin : function( content ) { alert(content); } }; $.fn.box = 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").box(); //call init function; //set box width 200px. $("div").box({width: '377px'}); //call init function with options //set box width 377px. $("div").box('hide'); //call hide funtion //div hide $("div").box('spin', 'This is box.'); //call spin function with argument //This is box.
這樣就可以依照參數的不同去執行不同的動作,然後又屬於同一隻plugin內,不需要為每種動作都建立一個plugin,我覺得很方便。
事件(Events)
在寫plugin時,一定會用到許多事件問題,常常要綁定一些事件,例如:「click」「blur」這類的事件要處理,在有些情況下,必須要讓這些事件停止動作,我們就必須「unbind」這些事件。所以我們常常會這樣:
(function($){ var methods = { init: function() { return this.each(function(){ $(window).bind('click', methods.start); //未加入namespacing ); }, stop: function() { return this.each(function(){ $(window).unbind('click'); //有可能干擾到其他相同類型事件 }); }, start: function(){ .......... } } $.fn.runner = 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);
如果照上面那樣寫的話,在初始化runner這個物件時,會綁定click事件,這沒有甚麼太大問題,但是當執行stop時,避免unbind「click」時干擾到其他事件,所以我們可以這樣寫:
var methods = { init: function() { return this.each(function(){ $(window).bind('click.runner', methods.start); //加入了namespacing ); }, stop: function() { return this.each(function(){ $(window).unbind('click.runner'); //或是 $(window).unbind('.runner'); //這樣就不會影響其他的事件 }); }, start: function(){ .......... } } $.fn.runner = 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' ); } };
這樣寫的話就可以緊限於這個物件的事件,而不去影響到其他plugin物件的運作。
沒有留言:
張貼留言