当你适应了jQuery,并且想学习怎么写自己的插件,好的,你真是个爱学习的人啊。使用插件和方法来扩展jQuery非常的强大,并且通过抽象你的大部分的聪明的方法到插件中你可以节约大量的开发时间。这篇文章会为你写插件显示最基本的技能,最佳实践和一些常遇到的错误。
开始:
写jQuery的插件,开始在你的插件名字的属性中为jQuery.fn对象增加一个新的函数的属性:
jQuery.fn.myPlugin = function() {
// Do your awesome plugin stuff here
};
不过,我们非常喜爱的$符号在哪呢?它是在那儿,但是我们必须保证我们的$符号不和别的libraries产生冲突.
传递jQuery到一个自我执行的函数(闭包),然后让$符号(作为形参)作为jquery对象,这样$符号就不会在我的执行范围内被别的库重写了.这个是一个最佳实践的实现
(function( $ ){
$.fn.myPlugin = function() {
// Do your awesome plugin stuff here
};
})( jQuery );
上下文
现在我们拥有我们的插件,我们可以开始写我们自己实际的插件代码,不过在我们写之前,我们说一说我们的开发环境的一个词.在插件函数的当前范围内,this关键词代表引用jquery插件的jQuery对象.在jQuery介绍一个回调,this关键字代表的是一个自然的dom元素,这个经常导致开发者在jQuery函数中使用$符号来包裹this关键词,这是一个常犯的错误.
(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 );
基础
现在我们知道了插件的上下文,现在我们使用jquery的插件来干点什么
(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
这是一个返回最高的div高度的一个简单的插件。
保持链式可用
前面的例子我们返回了一个页面的最高的vid的一个整数值,不过我们经常使用一个插件通过某种方式来简单的修改元素的集合。并且在链式中传递他们到下一个方法。这是一个非常好的设计,并也是jquey如此流行的一个原因,所以维持一个插件的链式调用,你必须确保插件返回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,所以如果你的插件不是返回一个固定的值,你应该一直返回this关键字在当前插件的函数范围内。和你想象的一样,你传递到插件中的参数嵌套传递到我们插件的当前的范围内。所以在前面的例子中,‘width'字符串变为了插件函数的type参数。
默认和选项
一些复杂并且习惯性的插件提供了很多的选项,当插件插入的时候有一个默认的可扩展的设置是一个最佳实践。这样你就可以避免使用非常多的参数,而使用少数的参数来重载默认的参数。
(function( $ ){
$.fn.tooltip = function( options ) {
var settings = {
'location' : 'top',
'background-color' : 'blue'
};
return this.each(function() {
// If options exist, lets merge them
// with our default settings
if ( options ) {
$.extend( settings, options );
}
// Tooltip plugin code here
});
};
})( jQuery );
$('div').tooltip({
'location' : 'left'
});
在这个例子中,使用给定的options来调用tooltip插件后,默认的setting被重载为‘left’,而默认的背景色的设置仍然是默认的‘blue’,
所以最后的设置看起来像这样:
{
'location' : 'left',
'background-color' : 'blue'
}
通过提供一个高效可配置的插件,而不是给要发者者定义所以的变量options是一个非常好的方式。
空间
对插件开发而言,一个合适的命名空间是插件开发非常重要的一部分。一个好的命名空间可以让你的插件被别的插件和一个页面的代码重写的机会非常的少。命名空间也可以使你的开发生活更加的容易,因为它能够更好的保存方法,事件,数据的路径。
插件的方法
在任何的情况下,我们都不应该要求在一个单独的插件在jQuery的fn对象下定义多个命名空间。
(function( $ ){
$.fn.tooltip = function( options ) { // THIS };
$.fn.tooltipShow = function( ) { // IS };
$.fn.tooltipHide = function( ) { // BAD };
$.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
$('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插件交互的一种标准。并被无数的插件使用包括使用最广的jQueryUI。
事件
很少有人知道bind方法允许命名空间绑定事件。如果你的插件绑定一个事件,命名空间是一个好的实践。这样,如果你想以后unbind事件,你能在不影响其他地方绑定了相同方法的情况下,unbind这个事件(大家看例子,具体的看unbind方法的应用),你可以通过增加“.<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方法被初始化,它通过window的resize方法绑定了 'tooltip'命名空间下的reposition方法。然后,开发者需要销毁tooltip,我们可以通过传递命名空间unbind事件的绑定。在这个例子中使用'tooltip'去解除绑定。这样我们就可以在插件外也可能有绑定事件的情况下安全的解除绑定。
数据
在我们插件开发的过程中,我们经常需要在给定的元素初始化后保存状态或者check。使用jQuery的data的方法是在每一个元素上保持track和变量的一个很好的方式。与我们使用不同的名字的独立的data保持track和变量相比保持我们最好使用一个单独的对象去装所以的变量和使用一个单独的数据空间去访问对象
(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帮助我们通过调用你的插件的方法保持变量和状态的track,吧你的数据命名在一个对象使我们可以很方便的访问我们的插件的属性。如果你需要移除,也可以很方便的减少数据的命名空间。