以前寫js的時候都沒有注意一些封裝插件的方法和技巧,如今將jquery的文檔翻譯一下,在自己學習的同時也給跟我類似的菜鳥一點精神食糧吧~親~
一、開始
寫一個插件,首先是要往 jquery.fn 對象中添加一個由你命名的function對象
jQuery.fn.myPlugin = function() {
// code
};
如果要使用我們熟悉的 $ 符號,並不希望它與其他腳本庫沖突,那么如下
(function( $ ) {
$.fn.myPlugin = function() {
// code
};
})( jQuery );
現在我們就能用美元符號代替那個麻煩的“jQuery”了
二、背景
現在我們可以開始開發我們自己的插件了,但在此之前,我們必須注意一點,在我們所編寫的插件function的作用域內,this關鍵字所代表的是調用該插件的jquery對象。
這是一個常見的錯誤,因為在jquery的回調函數里this關鍵字往往是表示一個DOM元素,這導致this關鍵字總被過度封裝。
(function( $ ){
$.fn.myPlugin = function() {
// 不需要寫成$(this)是因為這里的this已經是一個jquery對象
// $(this) 代表的意思則變成了 $($('#element'));
this.fadeIn('normal', function(){
// 這里的this是代表一個DOM元素
});
};
})( jQuery );
$('#element').myPlugin();
三、基礎知識
現在我們了解了jquery插件的背景,現在我們寫一個小demo來看看插件是怎么實現的
(function( $ ){
$.fn.maxHeight = function() {
var max = 0;
this.each(function() {
max = Math.max( max, $(this).height() );
});
return max;
};
})( jQuery );
var tallest = $('div').maxHeight(); // 返回最高的div的height
這是一個簡單的例子
四、保持鏈接性
前面的例子返回了一個div的高度值,但通常插件是簡單的修改集合的元素,並通過鏈將元素傳遞到下一個方法執行。
所以為了保持連接性,我們必須確保我們的插件將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方法可以繼續操作這些jquery集合,例如.css。
所以你的插件如果不返回一個固有值,你應該在你插件function的作用域里返回this關鍵字。
此外,如你所想的,你傳遞給你插件調用的參數獲得了你插件function的作用域(好吧。。。我承認這句不太會翻。。。大概意思就是傳進來的參數在作用域里都可用吧,廢話@_@~!)。
所以在前面的例子中,字符串‘width’在插件函數中變為了參數‘type’。
五、默認值(defaults) 和 配置(options)
對於更復雜的和可配置的插件提供了許多options,當插件調用時,具有可擴展的默認設置(用$.extend)是一種最好的實現方法。
所以與其調用的插件擁有大量的參數,不如調用這個插件時只有一個參數,但這個參數是一個可重寫設置的object對象。
這里是如何實現的例子
(function( $ ){
$.fn.tooltip = function( options ) {
// 創建一些默認值, 用提供的options來擴展
var settings = $.extend( {
'location' : 'top',
'background-color' : 'blue'
}, options);
return this.each(function() {
// code
});
};
})( jQuery );
$('div').tooltip({
'location' : 'left'
});
在這個例子里,用給定的options調用tooltip插件之后,默認的location設置被重新設置為‘left’,而 background-color還是默認的‘blue’。
所以最終的settings對象應該是:
{
'location' : 'left',
'background-color' : 'blue'
}
這是一個偉大的方式,提供了一個不需要開發人員定義所有有效options的高度可配置插件。
六、命名空間(namespace)
適當的命名空間對於插件開發是一個非常重要的部分。
正確的命名空間可以確保你的插件只有極小的可能被同一個page的其他插件或者代碼給覆蓋。
命名空間可以讓你作為插件開發者的生活更輕松,因為它能幫助你更好的跟蹤你的method、event和數據。
6.1 插件的方法(method)
在任何情況下一個單獨的插件都要求在jquery.fn對象里有一個以上的命名空間。
(function( $ ){
$.fn.tooltip = function( options ) {
// THIS
};
$.fn.tooltipShow = function( ) {
// IS
};
$.fn.tooltipHide = function( ) {
// BAD
};
$.fn.tooltipUpdate = function( content ) {
// !!!
};
})( jQuery );
這個是不好的,因為它使jquery.fn命名空間變得雜亂。
為了解決這個問題,你應該收集你所有的插件里的方法到一個object對象,並且通過傳遞這個方法的name字符串到插件來調用它們。
(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 );
// calls the init method
$('div').tooltip();
// calls the init method
$('div').tooltip({
foo : 'bar'
});
// calls the hide method
$('div').tooltip('hide');
// calls the update method
$('div').tooltip('update', 'This is the new tooltip content!');
這種類型的插件架構允許你將你所有的方法封裝在插件的父封閉(父作用域?)中,並首先傳入方法名稱字符串來調用它們,然后為這些方法傳入你所需要的參數。
在jquery plugin社區這類方法的封裝和結構是一個標准,它被無數插件所使用,包括了jqueryUI的插件和部件。
6.2 事件(Event)
一個鮮為人知的綁定方法的特色是允許命名已綁定的方法。 如果你的插件綁定了一個事件,一個很好的方法是命名它(意思應該就是例子中那種通過命名空間方法傳事件名字符串來調用吧?!)
這樣,如果你以后要解除綁定(unbind),這樣做可以排除可能綁定到同一個事件類型的其他事件的干擾。
你可以通過追加(appending)“.<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方法初始化時,它在“tooltip”命名空間下將reposition方法綁定到了window的resize事件上。
之后,如果開發者需要銷毀tooltip,我們可以通過傳入它的命名到unbind方法將插件事件解除綁定(unbind),在這個例子里是“tooltip”。
這允許我們安全的解除事件綁定,排除了意外解除掉插件外綁定的事件的情況。
6.3 數據(data)
常常在插件開發的時候,如果你的插件已經初始化一個給定的元素,你需要保持它的狀態或者檢查它。
使用jquery的data方法是一個偉大的方法以保持對每一個基本元素的變量的跟蹤。
然而,最好使用一個object對象容納你所有的變量,並且通過一個單獨的data命名去訪問這個object,而不是持續跟蹤一堆不同名稱的分散的數據。
(function( $ ){
var methods = {
init : function( options ) {
return this.each(function(){
var $this = $(this),
data = $this.data('tooltip'),
tooltip = $('<div />', {
text : $this.attr('title')
});
// 如果插件已經初始化
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幫助你在你的插件方法里跟蹤變量和狀態。命名你的數據到一個object對象,這樣你就能很輕松的從一個中心位置訪問到你插件的所有屬性,並且能輕松取消你想要移除的數據命名。
七、總結和最佳做法
編寫jquery插件能使利用高效的庫(library),以及抽象最靈活有用的功能,使之成為可重用的代碼,可以節省你的時間和使你的開發更高效。
下面是一個簡單的總結,請在下一次開發jquery插件時牢記:
1、始終將您的插件放在一個閉包中:
(function( $ ){ /* plugin goes here */ })( jQuery );
2、在你的插件function的作用域里不要重復封裝this關鍵字
3、除非你的插件要返回一個固定值,否則使插件總是返回this關鍵字以保持連續性
4、與其使用大量的參數,不如將你的設置傳入一個可擴展你插件默認值的object對象中。
5、不要使一個插件具有超過1個命名空間,導致jquery.fn對象混亂。
6、始終命名(namespace)你的方法、事件和數據。
