近期要准备一个web前端技术交流会的内容,所以陆续会有一些整理的资料发布,JQuery目 前在组内日常开发中占据了重要地位,但各自为战的情况很明显,要做到重用和通用,形成插件是不错的办法,特别是基于JQuery的插件,具有使用简单,可 参数化配置等优点。这篇文章就介绍了如何开发JQuery的插件。
我已经开发基于JQuery的插件有一段时间了,对于各种形式和要求的插件开发有了较好的掌握。在这里,我将在本文中分享我认为十分有用的插件开发 方式。当前前提是假定你对JQuery的插件开发有一定了解,如果你是插件开发的新手,不妨先看看jQuery官网上的the jQuery Authoring Guidelines。
我认为以下插件开发模式是必须应该掌握的:
1.在JQuery命名空间内声明一个特定的命名
2.接收参数来控制插件的行为
3.提供公有方法访问插件的配置项值
4.提供公有方法来访问插件中其他的方法(如果可能的话)
5.保证私有方法是私有的
6.支持元数据插件
下面,我将逐一讲述上面的内容,并在同时给出相关的简单插件开发代码。
1.在JQuery命名空间内声明一个特定的命名
这意味着开发的是一个单一命名的插件脚本,如果你的脚本包含多个插件或者有补充性质的插件,比如$.fn.doSomething() 和$.fn.undoSomething(),那你得声明多个命名了。但是总体来说,当开发一个插件时,我们应该努力做到用一个单一的命名来搞定整个插 件。
在例子中,我们将声明一个名为“hilight”的插件。
1 $.fn.hilight = function() {
2 // Our plugin implementation code goes here.
3 };
我们可以这样调用:
$(’#myDiv’).hilight();
但是假如我们需要打破这种单一的命名和调用方式呢?有很多理由支持我们这么做:设计上的需要;更加简单和可读的配置;而且那样将更加符合OO的要求。
在没有给命名空间来到麻烦的前提下,将插件的部署打破成为多个函数的形式将是十分繁琐的。我们通过认识并利用JavaScript中 functions是最高层的对象,和其他对象一样,functions可以被赋予属性,前面我们已经将hilight命名声明在了JQuery的原型对 象上,那么,其实,其他的我们想扩展的属性或对象都能够在hilight上进行声明。稍后将详细讲述此点。
2.接收参数来控制插件的行为
来为我们的hilight插件添加指定前景和背景色的功能,我们需要在函数中允许一个object类型的选项设置。如下所展示的那样:
1 $.fn.hilight = function(options) {
2 var defaults = {
3 foreground: ‘red‘,
4 background: ‘yellow‘
5 };
6 // Extend our default options with those provided.
7 var opts = $.extend(defaults, options);
8 // Our plugin implementation code goes here.
9 };
现在,我们的插件可以这样来调用:
$(’#myDiv’).hilight({
foreground: ‘blue’
});
3.提供公有方法访问插件的配置项值
上面的代码我们可以做一下改进,使得插件的默认值可以在插件之外被设置。这无疑是十分重要的,因为它使得插件用户可以使用最少的代码来修改插件配置,这其实是我们利用函数对象的开始。
// plugin definition
$.fn.hilight = function(options) {
// Extend our default options with those provided.
// Note that the first arg to extend is an empty object -
// this is to keep from overriding our ”defaults” object.
var opts = $.extend({}, $.fn.hilight.defaults, options);
// Our plugin implementation code goes here.
};
// plugin defaults - added as a property on our plugin function
$.fn.hilight.defaults = {
foreground: ‘red‘,
background: ‘yellow‘
};
4.提供公有方法来访问插件中其他的方法(如果可能的话)
这里要讲的方法和前面的讲解一脉相承,用此方法来扩展你的插件(而且能够让其他人进行扩展)是件很有意思的事情。例如,在扩展hilight插件 时,我们可以定义一个format方法用来格式化高亮显示的文本,原来的hilight插件和扩展了format方法的插件代码如下:
1 $.fn.hilight = function(options) {
2 // iterate and reformat each matched element
3 return this.each(function() {
4 var $this = $(this);
5
6 var markup = $this.html();
7 // call our format function
8 markup = $.fn.hilight.format(markup);
9 $this.html(markup);
10 });
11 };
12
13 // define our format function
14 $.fn.hilight.format = function(txt) {‘
15 return ‘<strong>‘ + txt + ‘</strong>’;
16 };
如前面所述,我们已经很容易的通过设置options对象的属性来允许一个回调函数来覆写默认的格式设置。在这里有另外一个非常棒的方法来个性化你 的插件,上面展示的方法实际上就是通过暴露format方法,使其可以被重新定义。这种做法使得其他人可以采用他们自己的习惯和方式来重写你的插件,这意 味着他们可以为你的插件写额外的扩展插件。
仔细考量一下前面我们用到的插件例子程序,你可能会想“我们究竟应该在什么时候使用这种插件方式来实现需求”的问题。一个来自现实应用中的插件便是“ Cycle Plugin”,它是一个支持多种滑动显示特效的插件,特效包括滚动、滑动和渐变等等。但是,实际上,并没有办法来定义每一个可能会用在滑动变幻上的特 效。这就是这种扩展方式的有用之处。“ Cycle Plugin”插件暴露了”transitions”对象,这使得用户只需要按照如下方式便可以添加自己的变幻定义:
$.fn.cycle.transitions = {
…
};
这种技巧使得用户可以定义或者采用自己习惯的方式来扩展“ Cycle Plugin”。
5.保证私有方法是私有的
上面提到的暴露插件中的公有方法的技巧使得插件能够被覆写,这将使插件变得十分灵活而强大,但至于哪一部分,那些属性和方法应该被暴露出来,你得小 心了。一旦使其能够被外界访问到,你就得注意到任何调用参数和语义化的变动都可能使其丧失向前的兼容性。作为一般准则,如果不确定是否应该暴露某个属性或 对象的话,那就最好别那样做。
那么我们应该怎样来定义多个方法而不至于使命名空间混乱并且保证不被暴露再外呢?这就是闭包的工作,为了便于演示,我们给插件加入了一个叫做 “debug”的功能,它用来记录firebug控制台所选择的网页元素数目。为了创建一个闭包,我们将整个功能的定义放入在一个function中了 (有关这方面的知识,可参见JQuery手册)。
1 // create closure
2 (function($) {
3 // plugin definition
4 $.fn.hilight = function(options) {
5 debug(this);
6
7 };
8 // private function for debugging
9 function debug($obj) {
10 if (window.console && window.console.log)
11 window.console.log(‘hilight selection count: ‘ + $obj.size());
12 };
13
14 // end of closure
15 })(jQuery);
// create closure
(function($) {
// plugin definition
$.fn.hilight = function(options) {
debug(this);
};
// private function for debugging
function debug($obj) {
if (window.console && window.console.log)
window.console.log(‘hilight selection count: ‘ + $obj.size());
};
// end of closure
})(jQuery);
debug方法在这里是无法被在插件以外访问到的,因此,我们称之为它是插件私有的。
6.支持元数据插件
根据你所写的插件的类型,为你的插件加入元数据插件的支持将使其变得更强大。就我个人来说,喜欢采用元数据插件的重要原因便是它可以让你使用定义之外的标签来覆写你的插件属性设置(这在创建demo和例子时十分有用),而且支持它十分的简单。
更新:这部分内容可以在本文的评论中展开讨论(既然有争议的话)
1 // plugin definition
2 $.fn.hilight = function(options) {
3
4 // build main options before element iteration
5 var opts = $.extend({}, $.fn.hilight.defaults, options);
6 return this.each(function() {
7 var $this = $(this);
8 // build element specific options
9 var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
10
改动部分的代码会做如下的事情:
*测试metadata插件是否可用
*如果可以,将用metadata扩展options对象
这被加入到jQuery.extend,作为其最后一个参数,所以它可以覆写任何其他参数设置。现在我们可以通过下面的方式控制其行为:
<!– markup –>
<div class=“hilight { background: ‘red’, foreground: ‘white’ }“>Have a nice day!</div>
<div class=“hilight { foreground: ‘orange’ }“>Have a nice day!</div>
<div class=“hilight { background: ‘green’ }“>Have a nice day!</div>
而在调用方面,我们通过一行简单的代码就可以实现预期的效果:
$(’.hilight’).hilight();
将上面所述内容涉及到的代码放在一起,完整的例子程序代码如下:
1 //
2 // create closure
3 //
4 (function($) {
5 //
6 // plugin definition
7 //
8 $.fn.hilight = function(options) {
9 debug(this);
10 // build main options before element iteration
11 var opts = $.extend({}, $.fn.hilight.defaults, options);
12 // iterate and reformat each matched element
13 return this.each(function() {
14 $this = $(this);
15 // build element specific options
16 var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
17 // update element styles
18 $this.css({
19 backgroundColor: o.background,
20 color: o.foreground
21 });
22 var markup = $this.html();
23 // call our format function
24 markup = $.fn.hilight.format(markup);
25 $this.html(markup);
26 });
27 };
28 //
29 // private function for debugging
30 //
31 function debug($obj) {
32 if (window.console && window.console.log)
33 window.console.log(‘hilight selection count: ‘ + $obj.size());
34 };
35 //
36 // define and expose our format function
37 //
38 $.fn.hilight.format = function(txt) {
39 return ‘<strong>‘ + txt + ‘</strong>‘;
40 };
41 //
42 // plugin defaults
43 //
44 $.fn.hilight.defaults = {
45 foreground: ‘red‘,
46 background: ‘yellow‘
47 };
48 //
49 // end of closure
50 //
51 })(jQuery);