[js插件开发教程]原生js仿jquery架构扩展开发选项卡插件
分类:
IT文章
•
2022-03-06 23:45:51
![[js插件开发教程]原生js仿jquery架构扩展开发选项卡插件](/default/index/img?u=aHR0cHM6Ly9wMi5waXFzZWxzLmNvbS9wcmV2aWV3LzYwNy85NjgvNTEvYXJjaGl0ZWN0dXJlLWJ1aWxkaW5nLWZ1dHVyZS1zcGFjZS5qcGc=&w=245&h=&w=700)
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