jquery插件一般是这么干的: $.fn.插件名称 = function(){}, 把插件的名称加在.fn上,在源码里面实际上是扩展到构造函数的原型对象上,如果你没看过jquery的源代码,或者你曾经看过,但是不知道为什么把插件扩展到fn上,那么本篇文章就能解答你的疑惑。关于jquery插件开发方式,可以参考我的这篇文章: [js高手之路]jquery插件开发实战-选项卡详解
关于选项卡这个功能具体怎么做,不在这里详解,这个是入门级的功能,本文重在讨论插件开发的架构,扩展,以及参数设置。
如果你使用过jquery的选项卡插件,或者其他类型的插件,他们一般都是这么调用的:
$( ".tab" ).tabs( {} )
$(".tab").tabs( function(){} );
一种是传递参数定制插件行为
一种是传递函数定制插件行为
$(".tab") 选择到元素,然后返回的是jquery对象
tabs方法扩展在fn上就是扩展都jquery构造函数的原型对象上, 那么对象( $(".tab") )调用原型对象上的方法( tabs )当然就顺利成章了。
所以jquery插件扩展本质就是: 构造函数 + 原型对象扩展方法
定义一个构造+原型的方式,下面代码的原理,我在这篇文章有详细论述: [js高手之路] 设计模式系列课程 - jQuery的链式调用与灵活的构造函数
1 var G = function( selectors, context ){
2 return new G.fn.init( selectors, context );
3 }
4 G.fn = G.prototype = {
5 length : 0,
6 constructor : G,
7 size : function(){
8 return this.length;
9 },
10 init : function( selector, context ){
11 this.length = 0;
12 context = context || document;
13 if ( selector.indexOf( '#' ) == 0 ){
14 this[0] = document.getElementById( selector.substring( 1 ) );
15 this.length = 1;
16 }else {
17 var aNode = context.querySelectorAll( selector );
18 for( var i = 0, len = aNode.length; i < len; i++ ) {
19 this[i] = aNode[i];
20 }
21 this.length = len;
22 }
23 this.selector = selector;
24 this.context = context;
25 return this;
26 }
27 }
28
29 G.fn.init.prototype = G.fn;
View Code
接下来,我们还要添加一个插件扩展机制:
1 G.extend = G.fn.extend = function () {
2 var i = 1,
3 len = arguments.length,
4 dst = arguments[0],
5 j;
6 if (dst.length === undefined) {
7 dst.length = 0;
8 }
9 if (i == len) {
10 dst = this;
11 i--;
12 }
13 for (; i < len; i++) {
14 for (j in arguments[i]) {
15 dst[j] = arguments[i][j];
16 dst.length++;
17 }
18 }
19 return dst;
20 };
View Code
在这篇文章: [js高手之路] 设计模式系列课程 - jQuery的extend插件机制 有详细的论述,extend插件扩展机制
像使用jquery一样暴露接口:
var $ = function( selectors, context ){
return G( selectors, context );
}
window.$ = $;
这个插件的扩展机制和元素选择机制就完成了,如果要扩展插件,只要在
G.fn上扩展插件的名称即可,如:
1 G.fn.tabs = function( options ){
2 options = options || {};
3 var defaults = {
4 contentClass : 'tab-content',
5 navClass : 'tab-nav',
6 activeClass : 'active',
7 triggerElements : '*',
8 activeIndex : 0,
9 evType : 'click',
10 effect : 'none'
11 };
12
13 var opt = G.extend( {}, defaults, options );
14 return this;
15 }
这样,我们就在G的原型对象上扩展了一个tabs( 选项卡 )插件
options可以定制插件的行为:
contentClass : 'tab-content', 选项卡内容区域的class名称
navClass : 'tab-nav', 标签卡区域的class名称
activeClass : 'active', 标签卡默认选择的class名称:active
triggerElements : '*', 标签卡默认触发元素
activeIndex : 0, 默认选中第几个标签卡
evType : 'click', 选项卡触发的事件类型
effect : 'none' 是否有过渡特效:如透明度
var opt = G.extend( {}, defaults, options );
这一段是把定制的配置和默认配置合成到一个对象opt里面,后面的插件行为,就可以根据opt的配置进行定制,这是插件开发参数定制中,常用的一招。
这样做的好处,可以防止污染默认配置defaults
1 var tabContent = this[0].querySelector( "." + opt.contentClass ); 2 var tabContentEle = tabContent.children; 3 var tabNavEle = this[0].querySelectorAll( "." + opt.navClass + '>' + opt.triggerElements ); 4 5 var _contentLen = tabContentEle.length; 6 var _index = opt.activeIndex;
获取对应的元素。
有了选项卡的元素和配置,我们就开始做业务处理(为所有选项卡添加处理的事件,进行选项卡切换)
定义一个专门的对象_api = {}, 扩展业务api
1 G.fn.tabs = function( options ){
2 options = options || {};
3 var defaults = {
4 contentClass : 'tab-content',
5 navClass : 'tab-nav',
6 activeClass : 'active',
7 triggerElements : '*',
8 activeIndex : 0,
9 evType : 'click',
10 effect : 'none'
11 };
12
13 var opt = G.extend( {}, defaults, options );
14
15 var tabContent = this[0].querySelector( "." + opt.contentClass );
16 var tabContentEle = tabContent.children;
17 var tabNavEle = this[0].querySelectorAll( "." + opt.navClass + '>' + opt.triggerElements );
18
19 var _contentLen = tabContentEle.length;
20 var _index = opt.activeIndex;
21
22 var _api = {};
23
24 _api.setIndex = function( index ){
25 //当前标签加上active样式,其余标签删除active样式
26 for ( var i = 0; i < _contentLen; i++ ) {
27 if ( tabNavEle[i].classList.contains( 'active' ) ) {
28 tabNavEle[i].classList.remove('active');
29 }
30 }
31 tabNavEle[index].classList.add( 'active' );
32 switch ( opt.effect ){
33 case 'fade':
34 break;
35 default:
36 for ( var i = 0; i < _contentLen; i++ ) {
37 tabContentEle[i].style.display = 'none';
38 }
39 tabContentEle[index].style.display = 'block';
40 _index = index;
41 }
42 }
43
44 _api.setIndex( _index ); //默认的选项卡
45
46 //所有的标签绑定事件
47 for( var i = 0, len = tabNavEle.length; i < len; i++ ) {
48 tabNavEle[i].index = i;
49 tabNavEle[i].addEventListener( opt.evType, function(){
50 var i = this.index;
51 _api.setIndex( i );
52 }, false );
53 }
54
55 return this;
56 }
View Code
完整的插件代码:
1 /**
2 * Created by ghostwu(吴华).
3 */
4 (function(){
5 var G = function( selectors, context ){
6 return new G.fn.init( selectors, context );
7 }
8 G.fn = G.prototype = {
9 length : 0,
10 constructor : G,
11 size : function(){
12 return this.length;
13 },
14 init : function( selector, context ){
15 this.length = 0;
16 context = context || document;
17 if ( selector.indexOf( '#' ) == 0 ){
18 this[0] = document.getElementById( selector.substring( 1 ) );
19 this.length = 1;
20 }else {
21 var aNode = context.querySelectorAll( selector );
22 for( var i = 0, len = aNode.length; i < len; i++ ) {
23 this[i] = aNode[i];
24 }
25 this.length = len;
26 }
27 this.selector = selector;
28 this.context = context;
29 return this;
30 }
31 }
32
33 G.fn.init.prototype = G.fn;
34 G.extend = G.fn.extend = function () {
35 var i = 1,
36 len = arguments.length,
37 dst = arguments[0],
38 j;
39 if (dst.length === undefined) {
40 dst.length = 0;
41 }
42 if (i == len) {
43 dst = this;
44 i--;
45 }
46 for (; i < len; i++) {
47 for (j in arguments[i]) {
48 dst[j] = arguments[i][j];
49 dst.length++;
50 }
51 }
52 return dst;
53 };
54
55 G.fn.tabs = function( options ){
56 options = options || {};
57 var defaults = {
58 contentClass : 'tab-content',
59 navClass : 'tab-nav',
60 activeClass : 'active',
61 triggerElements : '*',
62 activeIndex : 0,
63 evType : 'click',
64 effect : 'none'
65 };
66
67 var opt = G.extend( {}, defaults, options );
68
69 var tabContent = this[0].querySelector( "." + opt.contentClass );
70 var tabContentEle = tabContent.children;
71 var tabNavEle = this[0].querySelectorAll( "." + opt.navClass + '>' + opt.triggerElements );
72
73 var _contentLen = tabContentEle.length;
74 var _index = opt.activeIndex;
75
76 var _api = {};
77
78 _api.setIndex = function( index ){
79 //当前标签加上active样式,其余标签删除active样式
80 for ( var i = 0; i < _contentLen; i++ ) {
81 if ( tabNavEle[i].classList.contains( 'active' ) ) {
82 tabNavEle[i].classList.remove('active');
83 }
84 }
85 tabNavEle[index].classList.add( 'active' );
86 switch ( opt.effect ){
87 case 'fade':
88 break;
89 default:
90 for ( var i = 0; i < _contentLen; i++ ) {
91 tabContentEle[i].style.display = 'none';
92 }
93 tabContentEle[index].style.display = 'block';
94 _index = index;
95 }
96 }
97
98 _api.setIndex( _index ); //默认的选项卡
99
100 //所有的标签绑定事件
101 for( var i = 0, len = tabNavEle.length; i < len; i++ ) {
102 tabNavEle[i].index = i;
103 tabNavEle[i].addEventListener( opt.evType, function(){
104 var i = this.index;
105 _api.setIndex( i );
106 }, false );
107 }
108
109 return this;
110 }
111
112 var $ = function( selectors, context ){
113 return G( selectors, context );
114 }
115 window.$ = $;
116 })();
View Code
选项卡布局:
1 <!DOCTYPE html>
2 <html>
3 <head lang="en">
4 <!--作者:ghostwu(吴华)-->
5 <meta charset="UTF-8">
6 <title>选项卡插件 - by ghostwu</title>
7 <link rel="stylesheet" href="css/tab.css"/>
8 <script src="./js/tab.js"></script>
9 <script>
10 window.onload = function () {
11 // console.log( $(".tab1 .tab-nav li") );
12 // $( ".tab1" ).tabs( { 'evType' : 'mouseenter' } );
13 $( ".tab1" ).tabs();
14 }
15 </script>
16 </head>
17 <body>
18 <div class="main">
19 <div class="tab tab1">
20 <ul class="tab-nav">
21 <li class="active"><a href="javascript:;">标签1</a></li>
22 <li><a href="javascript:;">标签2</a></li>
23 <li><a href="javascript:;">标签3</a></li>
24 <li><a href="javascript:;">标签4</a></li>
25 </ul>
26 <div class="tab-content">
27 <p>内容1</p>
28 <p>内容2</p>
29 <p>内容3</p>
30 <p>内容4</p>
31 </div>
32 </div>
33 </div>
34 </body>
35 </html>
View Code
选项卡插件样式:
1 * {
2 margin: 0;
3 padding: 0;
4 }
5 body {
6 font-size: 14px;
7 font-family: Tahoma, Verdana,"Microsoft Yahei";
8 }
9 a{
10 text-decoration: none;
11 color:#000;
12 }
13 ul,li{
14 list-style-type: none;
15 }
16 img {
17 border:none;
18 }
19 .main {
20 width:960px;
21 margin:20px auto;
22 }
23 .tab{
24 margin: 0 auto 20px;
25 }
26 .tab1 .tab-nav{
27 margin-bottom:8px;
28 }
29 .tab .tab-nav {
30 overflow:hidden;
31 }
32 .tab1 .tab-nav .active{
33 border-bottom:1px solid #000;
34 }
35 .tab1 .tab-nav li {
36 float:left;
37 margin:0 10px;
38 }
39 .tab1 .tab-nav li a {
40 line-height:40px;
41 display:block;
42 }
43 .tab1 .tab-content {
44 height:250px;
45 overflow:hidden;
46 }
47 .tab1 .tab-content p {
48 height:250px;
49 background:#eee;
50 }
View Code
最终效果:
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。