您的位置:首页 > Web前端 > JQuery

jQuery插件开发全解析

2012-07-09 22:46 435 查看
jQuery插件的开发包括两种:

一种是类级别的插件开发,即给jQuery添加新的全局函数,相当于给jQuery类本身添加方法。jQuery的全局函数就是属于jQuery命名空间的函数,另一种是对象级别的插件开发,即给jQuery对象添加方法。下面就两种函数的开发做详细的说明。

1、类级别的插件开发

类级别的插件开发最直接的理解就是给jQuery类添加类方法,可以理解为添加静态方法。典型的例子就是$.AJAX()这个函数,将函数定义于jQuery的命名空间中。关于类级别的插件开发可以采用如下几种形式进行扩展:

1.1添加一个新的全局函数

添加一个全局函数,我们只需如下定义:

jQuery.foo=function(){
alert('Thisisatest.Thisisonlyatest.');
};


1.2增加多个全局函数

添加多个全局函数,可采用如下定义:

jQuery.foo=function(){
alert('Thisisatest.Thisisonlyatest.');
};
jQuery.bar=function(param){
alert('Thisfunctiontakesaparameter,whichis"'+param+'".');
};
调用时和一个函数的一样的:jQuery.foo();jQuery.bar();或者$.foo();$.bar('bar');


1.3使用jQuery.extend(object); 

jQuery.extend({
foo:function(){
alert('Thisisatest.Thisisonlyatest.');
},
bar:function(param){
alert('Thisfunctiontakesaparameter,whichis"'+param+'".');
}
});
1.4使用命名空间
虽然在jQuery命名空间中,我们禁止使用了大量的javaScript函数名和变量名。但是仍然不可避免某些函数或变量名将于其他jQuery插件冲突,因此我们习惯将一些方法封装到另一个自定义的命名空间。
jQuery.myPlugin={
foo:function(){
alert('Thisisatest.Thisisonlyatest.');
},
bar:function(param){
alert('Thisfunctiontakesaparameter,whichis"'+param+'".');
}
};
采用命名空间的函数仍然是全局函数,调用时采用的方法:
$.myPlugin.foo();
$.myPlugin.bar('baz');




通过这个技巧(使用独立的插件名),我们可以避免命名空间内函数的冲突。

2、对象级别的插件开发

对象级别的插件开发需要如下的两种形式:、

形式1:

(function($){
$.fn.extend({
pluginName:function(opt,callback){
//Ourpluginimplementationcodegoeshere.
}
})
})(jQuery);


形式2:

(function($){
$.fn.pluginName=function(){
//Ourpluginimplementationcodegoeshere.
};
})(jQuery);


上面定义了一个jQuery函数,形参是$,函数定义完成之后,把jQuery这个实参传递进去.立即调用执行。这样的好处是,我们在写jQuery插件时,也可以使用$这个别名,而不会与prototype引起冲突.

2.1在JQuery名称空间下申明一个名字

这是一个单一插件的脚本。如果你的脚本中包含多个插件,或者互逆的插件(例如:$.fn.doSomething()和$.fn.undoSomething()),那么你需要声明多个函数名字。但是,通常当我们编写一个插件时,力求仅使用一个名字来包含它的所有内容。我们的示例插件命名为“highlight“

$.fn.hilight=function(){
//Ourpluginimplementationcodegoeshere.
};
我们的插件通过这样被调用:
$('#myDiv').hilight();


但是如果我们需要分解我们的实现代码为多个函数该怎么办?有很多原因:设计上的需要;这样做更容易或更易读的实现;而且这样更符合面向对象。这真是一个麻烦事,把功能实现分解成多个函数而不增加多余的命名空间。出于认识到和利用函数是javascript中最基本的类对象,我们可以这样做。就像其他对象一样,函数可以被指定为属性。因此我们已经声明“hilight”为jQuery的属性对象,任何其他的属性或者函数我们需要暴露出来的,都可以在"hilight"函数中被声明属性。稍后继续。

2.2接受options参数以控制插件的行为

让我们为我们的插件添加功能指定前景色和背景色的功能。我们也许会让选项像一个options对象传递给插件函数。例如:



//plugindefinition
$.fn.hilight=function(options){
vardefaults={
foreground:'red',
background:'yellow'
};
//Extendourdefaultoptionswiththoseprovided.
varopts=$.extend(defaults,options);
//Ourpluginimplementationcodegoeshere.
};
我们的插件可以这样被调用:
$('#myDiv').hilight({
foreground:'blue'
});


2.3暴露插件的默认设置

我们应该对上面代码的一种改进是暴露插件的默认设置。这对于让插件的使用者更容易用较少的代码覆盖和修改插件。接下来我们开始利用函数对象。

//plugindefinition
$.fn.hilight=function(options){
//Extendourdefaultoptionswiththoseprovided.
//Notethatthefirstargtoextendisanemptyobject-
//thisistokeepfromoverridingour"defaults"object.
varopts=$.extend({},$.fn.hilight.defaults,options);
//Ourpluginimplementationcodegoeshere.
};
//plugindefaults-addedasapropertyonourpluginfunction
$.fn.hilight.defaults={
foreground:'red',
background:'yellow'
};
现在使用者可以包含像这样的一行在他们的脚本里:
//这个只需要调用一次,且不一定要在ready块中调用
$.fn.hilight.defaults.foreground='blue';
接下来我们可以像这样使用插件的方法,结果它设置蓝色的前景色:
$('#myDiv').hilight();


如你所见,我们允许使用者写一行代码在插件的默认前景色。而且使用者仍然在需要的时候可以有选择的覆盖这些新的默认值:

//覆盖插件缺省的背景颜色

$.fn.hilight.defaults.foreground='blue';

//...

//使用一个新的缺省设置调用插件

$('.hilightDiv').hilight();

//...

//通过传递配置参数给插件方法来覆盖缺省设置

$('#green').hilight({

foreground:'green'

});

2.4适当的暴露一些函数

这段将会一步一步对前面那段代码通过有意思的方法扩展你的插件(同时让其他人扩展你的插件)。例如,我们插件的实现里面可以定义一个名叫"format"的函数来格式化高亮文本。我们的插件现在看起来像这样,默认的format方法的实现部分在hiligth函数下面。

//plugindefinition
$.fn.hilight=function(options){
//iterateandreformateachmatchedelement
returnthis.each(function(){
var$this=$(this);
//...
varmarkup=$this.html();
//callourformatfunction
markup=$.fn.hilight.format(markup);
$this.html(markup);
});
};
//defineourformatfunction
$.fn.hilight.format=function(txt){
return'<strong>'+txt+'</strong>';
};


我们很容易的支持options对象中的其他的属性通过允许一个回调函数来覆盖默认的设置。这是另外一个出色的方法来修改你的插件。这里展示的技巧是进一步有效的暴露format函数进而让他能被重新定义。通过这技巧,是其他人能够传递他们自己设置来覆盖你的插件,换句话说,这样其他人也能够为你的插件写插件。

考虑到这个篇文章中我们建立的无用的插件,你也许想知道究竟什么时候这些会有用。一个真实的例子是Cycle插件.这个Cycle插件是一个滑动显示插件,他能支持许多内部变换作用到滚动,滑动,渐变消失等。但是实际上,没有办法定义也许会应用到滑动变化上每种类型的效果。那是这种扩展性有用的地方。
Cycle插件对使用者暴露"transitions"对象,使他们添加自己变换定义。插件中定义就像这样:

$.fn.cycle.transitions={

//...

};

这个技巧使其他人能定义和传递变换设置到Cycle插件。

2.5保持私有函数的私有性

这种技巧暴露你插件一部分来被覆盖是非常强大的。但是你需要仔细思考你实现中暴露的部分。一但被暴露,你需要在头脑中保持任何对于参数或者语义的改动也许会破坏向后的兼容性。一个通理是,如果你不能肯定是否暴露特定的函数,那么你也许不需要那样做。

那么我们怎么定义更多的函数而不搅乱命名空间也不暴露实现呢?这就是闭包的功能。为了演示,我们将会添加另外一个“debug”函数到我们的插件中。这个debug函数将为输出被选中的元素格式到firebug控制台。为了创建一个闭包,我们将包装整个插件定义在一个函数中。

(function($){
//plugindefinition
$.fn.hilight=function(options){
debug(this);
//...
};
//privatefunctionfordebugging
functiondebug($obj){
if(window.console&&window.console.log)
window.console.log('hilightselectioncount:'+$obj.size());
};
//...
})(jQuery);


我们的“debug”方法不能从外部闭包进入,因此对于我们的实现是私有的。

2.6支持Metadata插件

在你正在写的插件的基础上,添加对Metadata插件的支持能使他更强大。个人来说,我喜欢这个Metadata插件,因为它让你使用不多的"markup”覆盖插件的选项(这非常有用当创建例子时)。而且支持它非常简单。更新:注释中有一点优化建议。

$.fn.hilight=function(options){
//...
//buildmainoptionsbeforeelementiteration
varopts=$.extend({},$.fn.hilight.defaults,options);
returnthis.each(function(){
var$this=$(this);
//buildelementspecificoptions
varo=$.meta?$.extend({},opts,$this.data()):opts;
//...


这些变动行做了一些事情:它是测试Metadata插件是否被安装如果它被安装了,它能扩展我们的options对象通过抽取元数据这行作为最后一个参数添加到JQuery.extend,那么它将会覆盖任何其它选项设置。现在我们能从"markup”处驱动行为,如果我们选择了“markup”:

调用的时候可以这样写:jQuery.foo();或$.foo();

<!--markup-->
<divclass="hilight{background:'red',foreground:'white'}">
Haveaniceday!
</div>
<divclass="hilight{foreground:'orange'}">
Haveaniceday!
</div>
<divclass="hilight{background:'green'}">
Haveaniceday!
</div>
现在我们能高亮哪些div仅使用一行脚本:
$('.hilight').hilight();


2.7整合

下面使我们的例子完成后的代码:

//创建一个闭包
(function($){
//插件的定义
$.fn.hilight=function(options){
debug(this);
//buildmainoptionsbeforeelementiteration
varopts=$.extend({},$.fn.hilight.defaults,options);
//iterateandreformateachmatchedelement
returnthis.each(function(){
$this=$(this);
//buildelementspecificoptions
varo=$.meta?$.extend({},opts,$this.data()):opts;
//updateelementstyles
$this.css({
backgroundColor:o.background,
color:o.foreground
});
varmarkup=$this.html();
//callourformatfunction
markup=$.fn.hilight.format(markup);
$this.html(markup);
});
};
//私有函数:debugging
functiondebug($obj){
if(window.console&&window.console.log)
window.console.log('hilightselectioncount:'+$obj.size());
};
//定义暴露format函数
$.fn.hilight.format=function(txt){
return'<strong>'+txt+'</strong>';
};
//插件的defaults
$.fn.hilight.defaults={
foreground:'red',
background:'yellow'
};
//闭包结束
})(jQuery);


这段设计已经让我创建了强大符合规范的插件。我希望它能让你也能做到。

3、总结

jQuery为开发插件提拱了两个方法,分别是:

jQuery.fn.extend(object);给jQuery对象添加方法。

jQuery.extend(object);为扩展jQuery类本身.为类添加新的方法。

3.1jQuery.fn.extend(object);

fn是什么东西呢。查看jQuery代码,就不难发现。

jQuery.fn=jQuery.prototype={

init:function(selector,context){//.... 

//......

};

原来jQuery.fn=jQuery.prototype.对prototype肯定不会陌生啦。虽然javascript 没有明确的类的概念,但是用类来理解它,会更方便。jQuery便是一个封装得非常好的类,比如我们用语句 $("#btn1")会生成一个
jQuery类的实例。

jQuery.fn.extend(object);对jQuery.prototype进得扩展,就是为jQuery类添加“成员函数”。jQuery类的实例可以使用这个“成员函数”。

比如我们要开发一个插件,做一个特殊的编辑框,当它被点击时,便alert当前编辑框里的内容。可以这么做:

$.fn.extend({

alertWhileClick:function(){

$(this).click(function(){

alert($(this).val());

});

}

});

$("#input1").alertWhileClick();//页面上为:<inputid="input1"type="text"/>

$("#input1") 为一个jQuery实例,当它调用成员方法alertWhileClick后,便实现了扩展,每次被点击时它会先弹出目前编辑里的内容。

3.2jQuery.extend(object); 

为jQuery类添加添加类方法,可以理解为添加静态方法。如:

$.extend({

add:function(a,b){returna+b;}

});

便为 jQuery 添加一个为add 的 “静态方法”,之后便可以在引入jQuery 的地方,使用这个方法了,$.add(3,4);
//return7

----------------------------------------------------------------------------------------------------------------

/*!
*jQuery源码分析-extend函数
*jQuery版本:1.4.2
*
*----------------------------------------------------------
*函数介绍
*jQuery.extend与jQuery.fn.extend指向同一个函数对象
*jQuery.extend是jQuery的属性函数(静态方法)
*jQuery.fn.extend是jQuery函数所构造对象的属性函数(对象方法)
*
*----------------------------------------------------------
*使用说明
*extend函数根据参数和调用者实现功能如下:
*1.对象合并:
*对象合并不区分调用者,jQuery.extend与jQuery.fn.extend完全一致
*也就是说对jQuery对象本身及jQuery所构造的对象没有影响
*对象合并根据参数区分,参数中必须包括两个或两个以上对象
*如:$.extend({Object},{Object})或$.extend({Boolean},{Object},{Object})
*对象合并返回最终合并后的对象,支持深度拷贝
*
*2.为jQuery对象本身增加方法:
*这种方式从调用者和参数进行区分
*形式为$.extend({Object})
*这种方式等同于jQuery.{FnctionName}
*
*3.原型继承:
*原型继承方式可以为jQuery所构造的对象增加方法
*这种方式也通过调用者和参数进行区分
*形式为$.fn.extend({Object})
*这种方式实际上是将{Object}追加到jQuery.prototype,实现原型继承
*
*----------------------------------------------------------
*
*/

//jQuery.fn=jQuery.prototype
//jQuery.fn.extend=jQuery.prototype.extend
jQuery.extend=jQuery.fn.extend=function(){

//目标对象
vartarget=arguments[0]||{},

//循环变量,它会在循环时指向需要复制的第一个对象的位置,默认为1
//如果需要进行深度复制,则它指向的位置为2
i=1,

//实参长度
length=arguments.length,

//是否进行深度拷贝
//深度拷贝情况下,会对对象更深层次的属性对象进行合并和覆盖
deep=false,

//用于在复制时记录参数对象
options,

//用于在复制时记录对象属性名
name,

//用于在复制时记录目标对象的属性值
src,

//用于在复制时记录参数对象的属性值
copy;

//只有当第一个实参为true时,即需要进行深度拷贝时,执行以下分支
if(typeoftarget==="boolean"){
//deep=true,进行深度拷贝
deep=target;

//进行深度拷贝时目标对象为第二个实参,如果没有则默认为空对象
target=arguments[1]||{};

//因为有了deep深度复制参数,因此i指向的位置为第二个参数
i=2;
}

//当目标对象不是一个Object且不是一个Function时(函数也是对象,因此使用jQuery.isFunction进行检查)
if(typeoftarget!=="object"&&!jQuery.isFunction(target)){

//设置目标为空对象
target={};
}

//如果当前参数中只包含一个{Object}
//如$.extend({Object})或$.extend({Boolean},{Object})
//则将该对象中的属性拷贝到当前jQuery对象或实例中
//此情况下deep深度复制仍然有效
if(length===i){

//target=this;这句代码是整个extend函数的核心
//在这里目标对象被更改,这里的this指向调用者
//在$.extend()方式中表示jQuery对象本身
//在$.fn.extend()方式中表示jQuery函数所构造的对象(即jQuery类的实例)
target=this;

//自减1,便于在后面的拷贝循环中,可以指向需要复制的对象
--i;
}

//循环实参,循环从第1个参数开始,如果是深度复制,则从第2个参数开始
for(;i<length;i++){

//当前参数不为null,undefined,0,false,空字符串时
//options表示当前参数对象
if((options=arguments[i])!=null){

//遍历当前参数对象的属性,属性名记录到name
for(nameinoptions){

//src用于记录目标对象中的当前属性值
src=target[name];

//copy用于记录参数对象中的当前属性值
copy=options[name];

//存在目标对象本身的引用,构成死循环,结束此次遍历
if(target===copy){
continue;
}

//如果需要进行深度拷贝,且copy类型为对象或数组
if(deep&©&&(jQuery.isPlainObject(copy)||jQuery.isArray(copy))){

//如果src类型为对象或数组,则clone记录src
//否则colne记录与copy类型一致的空值(空数组或空对象)
varclone=src&&(jQuery.isPlainObject(src)||jQuery.isArray(src))?src:jQuery.isArray(copy)?[]:{};

//对copy迭代深度复制
target[name]=jQuery.extend(deep,clone,copy);

//如果不需要进行深度拷贝
}elseif(copy!==undefined){

//直接将copy复制给目标对象
target[name]=copy;
}
}
}
}

//返回处理后的目标对象
returntarget;
};

/**
*jQuery框架本身对extend函数的使用非常频繁
*典型示例为jQuery.ajax
*
*/

//使用extend对jQuery对象本身进行扩展,只给了一个参数对象
//该对象中的属性将被追加到jQuery对象中
jQuery.extend({

//jQuery.ajax
//$.ajax

//这里的origSettings参数是自定义的ajax配置
//jQuery对象本身有一个ajaxSettings属性,是默认的ajax配置
ajax:function(origSettings){

//这里使用extend对ajax配置项进行合并
//第一个参数表示进行深度拷贝
//首先将第3个参数jQuery.ajaxSettings(即jQuery默认ajax配置)复制到第2个参数(一个空对象)
//然后将第4个参数(自定义配置)复制到配置对象(覆盖默认配置)
//这里的s就得到了最终的ajax配置项
vars=jQuery.extend(true,{},jQuery.ajaxSettings,origSettings);

//其它相关代码...(省略)
}
});




                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: