0%

基于jQuery的选项卡封装(插件)

前言

以前在写网页上常用的功能时,经常差不多同样的js代码会重复好几遍,而重来没想过把它封装起来,增加代码的复用性。最近把一些常用的功能封装了一下,而jquery插件式的封装方法也是几经周折、查了一些资料才弄出来的。下面就用最常用的选项卡为例子来说明一下吧。


正文

首先,jquery官方是提供了一个写插件的模板的,像superSlide等插件就是基于这样的模板写的。然而一开始我并不知道有这样一个模板,我想写出类似于superSlide这样调用的效果$(selector).slide({}),我当时的理解是:slide()肯定是一个jquery对象$(selector)的方法,也是因为原型那一块没学好,在那里苦思冥想怎么把这个方法挂到每一个jquery对象的实例上呢?现在可以事后诸葛亮的说直接把方法挂在jquery对象的原型上,通过继承链继承不就好了?恩,扯远了,先把模板代码贴一下吧,然后再解释下这个模板:

jquery插件模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//自行引入jquery库
;(function($){
$.fn.plugin = function(options){ //plugin为插件名,可以自行修改
var defaults = {
//各种参数,各种属性,这里是默认配置
}

var opts = $.extend({},defaults,options);

this.each(function(){
//实现功能的代码都放在这里
});

return this; //返回基于选择器的jquery对象,保证链式操作
}
})(jQuery);
1
2
//调用时的代码示例
$('.tab').plugin({//这里就先不写了});

把上面的代码简化一下就是(function($){})(jQuery);,还有另一种写法(function($){}(jQuery));,效果是一样的 (其实jquery的源码也是采用这种形式的(function(window,undefined){})(window))。这种形式就是一个匿名函数自执行,把所有的代码封装在里面就避免了污染全局对象,在浏览器里也就是window对象。前面加一个;是为了避免与其它的库或代码产生”摩擦”。再看这段代码$.fn.plugin = function(options){}$.fn实际上就是jQuery的原型prototype,那$.fn.plugin就相当于在jQuery的原型上定义了一个方法,这个方法接收一个参数options,这个参数是一个对象。这个方法内部的代码又可以分为4大块:

  1. var defaults = {}; 把功能代码中可能会变化的变量(比如dom节点)提取出来,给一个默认的值,组成一个对象,方便调用者在调用的时候按照需求修改,如果调用的时候什么都不传,就用默认的。
  2. var opts = $.extend({},defaults,options); 关于$.extend()的具体用法,可以参看官方文档中对这个API的说明。其实粗略的理解就是把defaults和options这两个对象合并起来成为一个新的对象opts(后面功能代码里用到的变量都是用的opts这个对象的属性),options里的属性值会覆盖掉defaults里的属性值,options里没有的属性,就用defaults里提供的默认属性值。
  3. this.each(function(){}); 实现功能的代码都往这里面扔就好了,没什么好说的。
  4. return this; 返回值this就是对应dom节点的jquery对象,比如$('.tab')。加上这个返回值才能支持链式操作,比如$('.tab').plugin().sinbling()...

示例demo代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- html代码 -->
<div class="tab">
<div class="tab-title">
<ol class="clearfix">
<li>1</li>
<li>2</li>
<li>3</li>
</ol>
</div>
<div class="tab-cont">
<ul class="clearfix">
<li>内容1</li>
<li>内容2</li>
<li>内容3</li>
</ul>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
/* css代码 */
* { margin:0; padding:0;}
li { list-style: none;}
.clearfix:after {
content: "" ;
display: block ;
height: 0 ;
clear: both ;
visibility: hidden ;
}
.tab-title li{ float: left; width: 100px; height: 50px; text-align: center;cursor:pointer; line-height: 50px;}
.tab-title li.on { background: purple; color: #fff;}
.tab-cont li { width: 300px; height: 300px;text-align: center; border: 1px solid #333;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* jquery-funtab-1.0.js */
;(function($){
$.fn.funTab = function(options){
$.fn.funTab.defaults = {
titItem: '.tab-title li', //选项卡导航对应的选择器
contItem: '.tab-cont li', //选项卡内容区对应的选择器
trigger: 'mouseover', //事件
titOnClassName: 'on' //导航选中样式类名
};

var opts = $.extend({},$.fn.funTab.defaults,options);

this.each(function(){
var funTaber = $(this); //这里this就是整个选项卡对应的jquery对象,先存一下,避免与下面的事件函数里的this混淆

//初始化
funTaber.find(opts.titItem).eq(0).addClass(opts.titOnClassName);
funTaber.find(opts.contItem).eq(0).show().siblings().hide();
var index;
//这里的写法其实和下面的bind写法效果一样,推荐用bind
//funTaber.find(opts.titItem)[opts.trigger](function(){
// $(this).addClass(opts.titOnClassName).siblings().removeClass(opts.titOnClassName);
// var index = funTaber.find(opts.titItem).index(this);
// funTaber.find(opts.contItem).eq(index).show().siblings().hide();
//});
funTaber.find(opts.titItem).bind(opts.trigger,function(){
$(this).addClass(opts.titOnClassName).siblings().removeClass(opts.titOnClassName);
var index = funTaber.find(opts.titItem).index(this);
funTaber.find(opts.contItem).eq(index).show().siblings().hide();
})
});

return this;
}
})(jQuery);
1
2
3
4
5
//调用代码
//下面除了trigger外,其他的项都与默认的一致,其实是可以省略不写的,
$('.tab').funTab({
titItem:'.tab-title li',contItem:'.tab-cont li',trigger:'click',titOnClassName:'on'
});