众所周知,jQuery不仅仅是一个十分优秀的javaScript库,它还提供了十分方便而标准的插件拓展接口,使我们编写的插件拥有统一的使用接口、事件机制,大大降低了开发者学习和集成插件的成本。
声明jQuery插件的方法十分简单,就是往jQuery.fn
追加一个属性即可
// myPlugin就是你要声明的插件的名称
jQuery.fn.myPlugin = function () {
// 在这里书写插件的相关代码
}
当然,我们一般更习惯使用美元符号$
而不是jQuery
。但是如果$
已经被占用了,那么为了避免产生冲突,我们一般会利用 IIFE:(Immediately Invoked Function Expression,立即调用的函数表达式),在函数体内使用$
指代jQuery
。这也应该我们最常见的插件声明方式:
(function($) {
$.fn.myPlugin = function () {
// 在这里编写插件的实现代码
};
})(jQuery);
下面演示一个返回当前页面中div
元素的最大高度的插件(请注意插件内各个this分别指代的是什么)
(function ($) {
$.fn.maxHeight = function () {
var max = 0;
// 这里的this是DOM元素列表
this.each(function() {
// 这里的this是单个DOM元素,下面将它封装成一个jQuery对象
max = Math.max(max, $(this).height());
});
return max;
};
})(jQuery);
var tallest = $('div').maxHeight();
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');
一些较为复杂、高度可定制的插件会有一堆配置参数,此时配置这些参数的默认值就变得十分重要了,这时jQuery本身提供的extend()
函数就十分有用了。
(function( $ ){
$.fn.tooltip = function( options ) {
// 合并默认配置与用户传入的配置
var settings = $.extend( {
'location' : 'top',
'background-color' : 'blue'
}, options);
return this.each(function() {
// 插件的主要逻辑代码
});
};
})( jQuery );
$('div').tooltip({
'location' : 'left'
});
那么最终生效的参数配置就为:
{
'location' : 'left',
'background-color' : 'blue'
}
假如我们要编写的插件不再只有一个函数了,而是有多个函数,之前的那种写法就很难再行得通了,例如:
(function( $ ){
$.fn.tooltip = function( options ) {
};
$.fn.tooltipShow = function( ) {
};
$.fn.tooltipHide = function( ) {
};
$.fn.tooltipUpdate = function( content ) {
};
})( jQuery );
不仅大大增加了命名冲突的风险,还大大增加了管理的难度,推荐的做法是引入命名空间,把所有的插件函数集中起来进行管理,例如:
(function( $ ){
// 将所有的接口函数统统用methods对象封装起来
var methods = {
init : function( options ) {
},
show : function( ) {
},
hide : function( ) {
},
update : function( content ) {
}
};
// tooltip就是我们暴露出去的命名空间
$.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 );
// 插件初始化(使用默认配置)
$('div').tooltip();
// 插件初始化(使用自定义配置)
$('div').tooltip({
foo : 'bar'
});
// 调用hide方法
$('div').tooltip('hide');
// 调用update方法
$('div').tooltip('update', 'This is the new tooltip content!');
此种做法,充分利用了javaScript的闭包机制,也是jQuery插件社区的标准做法,我们使用各种jQuery插件时应该也对这种写法有些印象吧
同样地,插件相关的专属事件也都应该由命名空间统一管理
(function( $ ){
var methods = {
init : function( options ) {
return this.each(function(){
$(window).on('resize.tooltip', methods.reposition);
});
},
destroy : function( ) {
return this.each(function(){
$(window).off('.tooltip');
})
},
reposition : function( ) {
},
hide : function( ) {
$(window).trigger('hidden.tooltip');
}
};
})( jQuery );
$('#fun').tooltip();
$('#someObj').on('hidden.tooltip', function(){···})
$('#fun').tooltip('hide');
$('#fun').tooltip('destroy');
这样,在插件初始化后,每次浏览器的窗口大小发生变化时就会触发它的reposition
函数,销毁时会自动把该事件监听解绑;而我们的someObj
元素也只会对tooltip
的hidden
事件发生响应,而无视其他组件或者插件的hidden
事件
如果我们的插件需要维护一些动态数据,或者我们需要确认我们的插件是否在对应元素上已经进行过初始化,如果已经进行过则无需再次进行初始化。。我们可以充分利用jQuery的dataAPI
(function( $ ){
var methods = {
init : function( options ) {
return this.each(function(){
var $this = $(this),
data = $this.data('tooltip'),
tooltip = $('', {
text : $this.attr('title')
});
// 如果还没进行初始化,则立即进行初始化
if ( ! data ) {
$(this).data('tooltip', {
target : $this,
tooltip : tooltip
});
}
});
},
destroy : function( ) {
return this.each(function(){
var $this = $(this),
data = $this.data('tooltip');
data.tooltip.remove();
$this.removeData('tooltip');
})
},
};
}
};
})( jQuery );