[js插件開發教程]實現一個比較完整的開源級選項卡插件


在這篇文章中,我實現了一個基本的選項卡功能:請猛擊后面的鏈接>>   [js插件開發教程]原生js仿jquery架構擴展開發選項卡插件.

還缺少兩個常用的切換(自動切換與透明度漸變),當然有朋友會說,還有左右,上下等等,這些動畫會放在焦點圖(幻燈片)插件系列.

(自動切換,停止控制,透明度漸變 ) 效果預覽:

自動切換的實現:

這個思路很簡單,開啟定時器,讓選項卡的索引+1,加到4的時候(選項卡的長度)從0開始

傳統做法:

index = 0

index++

if ( index == 4 ) {

index = 0

}

小技巧(估計很多人都沒有用過):

var i = ( index + 1 ) %  4

index為當前選中的選項卡 索引

當index = 0,他下一張就是1,  通過上面的取余操作,i = 1

當index = 3,他下一張就是0, 通過上面的取余操作,i = 0

這種方法不需要判斷邊界,只需要一句代碼。在實際開發中,把那個4替換成選項卡的長度

好了,關鍵的思路和技巧有了,我們開始拼接框架了:

 1         var defaults = {
 2             contentClass : 'tab-content',
 3             navClass : 'tab-nav',
 4             activeClass : 'active',
 5             triggerElements : '*',
 6             activeIndex : 0,
 7             evType : 'click',
 8             effect : 'none',
 9             auto : false,
10             delay : 3000,
11             duration : 1000
12         };

defaults參數,增加幾個配置:

effect: none(沒有特效) / fade( 透明度切換 )

auto: false(不會自動切換) / true ( 開啟自動切換 )

delay : 多少時間 切換一個選項卡

duration: 透明度開啟,這個才會用到,表示,多長時間內 完成透明度的切換

1 if ( options.effect == 'fade' ) {
2             tabContent.style.position = 'relative';
3             for( var i = 0; i < tabContentEle.length; i++ ) {
4                 tabContentEle[i].style.position = 'absolute';
5             }
6             tabContentEle[opt.activeIndex].style.zIndex = _contentLen + 1;
7             opt.delay += opt.duration;
8         }

當開啟透明度變化的時候,把選項卡元素設置成定位方式,當前選中的選項卡,層級為最高!!! ( 如果不是最高層級,那么默認是最后一個選項卡在最上面,所以 “內容4” 就會在最上層,顯然不是我們想要的結果)層級+定位 這一招也很常用,經常用來做顯示隱藏,和透明度變化.

根據opt配置,判斷是否開啟了auto自動切換功能

 1  //是否自動播放
 2         if ( opt.auto ) {
 3             for( var i = 0 ; i < tabNavEle.length; i++ ){
 4                 tabNavEle[i].index = i;
 5                 tabNavEle[i].onmouseover = function(){
 6                     _api.stop();
 7                     _api.setIndex( this.index );
 8                 };
 9                 tabNavEle[i].onmouseout = function(){
10                     _api.start();
11                     _api.setIndex( this.index );
12                 };
13             }
14             _api.start();
15         }

如果開啟了,做兩件事情:

1,調用start()函數,讓索引+1

2,選項卡導航部分,添加事件控制 自動播放的暫停和開始

start與stop方法?

 1 _api.stop = function(){
 2             timer && clearInterval( timer );
 3         };
 4 
 5         _api.start = function(){
 6             _api.stop();
 7             timer = setInterval( function(){
 8                 _api.next();
 9             }, opt.delay );
10         };

調用next方法,你應該猜得到next方法做的事情就是索引+1 吧

1  _api.next = function(){
2             var i = ( _index + 1 ) % _contentLen;
3             _api.setIndex( i );
4         };

索引+1之后,再切換選項卡

最后在setIndex方法:增加透明度變化

 1 if ( _index != index ) {
 2                         tabContentEle[_index].style.zIndex = _contentLen + 1;
 3                         for (var i = 0; i < tabContentEle.length; i++) {
 4                             if (i != _index) {
 5                                 tabContentEle[i].style.zIndex = ( index + _contentLen - ( i + 1 ) ) % _contentLen + 1;
 6                                 tabContentEle[i].style.opacity = 1;
 7                             }
 8                         }
 9                         animate(tabContentEle[_index], {'opacity': 0}, function () {
10                             tabContentEle[_index].style.zIndex = ( index + _contentLen - ( _index + 1 ) ) % _contentLen + 1;
11                             _index = index;
12                         });
13                     }

完整的js代碼有220行:

  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     function css(obj, attr, value) {
 56         if (arguments.length == 3) {
 57             obj.style[attr] = value;
 58         } else {
 59             if (obj.currentStyle) {
 60                 return obj.currentStyle[attr];
 61             } else {
 62                 return getComputedStyle(obj, false)[attr];
 63             }
 64         }
 65     }
 66 
 67     function animate(obj, attr, fn) {
 68         clearInterval(obj.timer);
 69         var cur = 0;
 70         var target = 0;
 71         var speed = 0;
 72         var start = new Date().getTime();//起始時間
 73         obj.timer = setInterval(function () {
 74             var bFlag = true;
 75             for (var key in attr) {
 76                 if (key == 'opacity') {
 77                     cur = css(obj, 'opacity') * 100;
 78                 } else {
 79                     cur = parseInt(css(obj, key));
 80                 }
 81                 target = attr[key];
 82                 speed = ( target - cur ) / 8;
 83                 speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
 84                 if (cur != target) {
 85                     bFlag = false;
 86                     if (key == 'opacity') {
 87                         obj.style.opacity = ( cur + speed ) / 100;
 88                         obj.style.filter = "alpha(opacity:" + ( cur + speed ) + ")";
 89                     } else {
 90                         obj.style[key] = cur + speed + "px";
 91                     }
 92                 }
 93             }
 94             if (bFlag) {
 95                 var end = new Date().getTime();//結束時間
 96                 console.log( '總計:',  ( end - start ) );
 97                 clearInterval(obj.timer);
 98                 fn && fn.call(obj);
 99             }
100         }, 30 );
101     }
102 
103     G.fn.tabs = function( options ){
104         options = options || {};
105         var defaults = {
106             contentClass : 'tab-content',
107             navClass : 'tab-nav',
108             activeClass : 'active',
109             triggerElements : '*',
110             activeIndex : 0,
111             evType : 'click',
112             effect : 'none',
113             auto : false,
114             delay : 3000,
115             duration : 1000
116         };
117 
118         var opt = G.extend( {}, defaults, options );
119 
120         var tabContent = this[0].querySelector( "." + opt.contentClass );
121         var tabContentEle = tabContent.children;
122         var tabNavEle = this[0].querySelectorAll( "." + opt.navClass + '>' + opt.triggerElements );
123 
124         var _contentLen = tabContentEle.length; //選項卡個數
125         var _index = opt.activeIndex;
126         var timer = null;
127 
128         if ( options.effect == 'fade' ) {
129             tabContent.style.position = 'relative';
130             for( var i = 0; i < tabContentEle.length; i++ ) {
131                 tabContentEle[i].style.position = 'absolute';
132             }
133             tabContentEle[opt.activeIndex].style.zIndex = _contentLen + 1;
134             opt.delay += opt.duration;
135         }
136 
137         var _api = {};
138 
139         _api.next = function(){
140             var i = ( _index + 1 ) % _contentLen;
141             _api.setIndex( i );
142         };
143 
144         _api.stop = function(){
145             timer && clearInterval( timer );
146         };
147 
148         _api.start = function(){
149             _api.stop();
150             timer = setInterval( function(){
151                 _api.next();
152             }, opt.delay );
153         };
154 
155         _api.setIndex = function( index ){
156             //當前標簽加上active樣式,其余標簽刪除active樣式
157             for ( var i = 0; i < _contentLen; i++ ) {
158                 if ( tabNavEle[i].classList.contains( 'active' ) ) {
159                     tabNavEle[i].classList.remove('active');
160                 }
161             }
162             tabNavEle[index].classList.add( 'active' );
163             switch ( opt.effect ){
164                 case 'fade':
165                     if ( _index != index ) {
166                         tabContentEle[_index].style.zIndex = _contentLen + 1;
167                         for (var i = 0; i < tabContentEle.length; i++) {
168                             if (i != _index) {
169                                 tabContentEle[i].style.zIndex = ( index + _contentLen - ( i + 1 ) ) % _contentLen + 1;
170                                 tabContentEle[i].style.opacity = 1;
171                             }
172                         }
173                         animate(tabContentEle[_index], {'opacity': 0}, function () {
174                             tabContentEle[_index].style.zIndex = ( index + _contentLen - ( _index + 1 ) ) % _contentLen + 1;
175                             _index = index;
176                         });
177                     }
178                     break;
179                 default:
180                     for ( var i = 0; i < _contentLen; i++ ) {
181                         tabContentEle[i].style.display = 'none';
182                     }
183                     tabContentEle[index].style.display = 'block';
184                     _index = index;
185             }
186         }
187 
188         _api.setIndex( _index ); //默認的選項卡
189 
190         //所有的標簽綁定事件
191         for( var i = 0, len = tabNavEle.length; i < len; i++ ) {
192             tabNavEle[i].index = i;
193             tabNavEle[i].addEventListener( opt.evType, function(){
194                 var i = this.index;
195                 _api.setIndex( i );
196             }, false );
197         }
198 
199         //是否自動播放
200         if ( opt.auto ) {
201             for( var i = 0 ; i < tabNavEle.length; i++ ){
202                 tabNavEle[i].index = i;
203                 tabNavEle[i].onmouseover = function(){
204                     _api.stop();
205                     _api.setIndex( this.index );
206                 };
207                 tabNavEle[i].onmouseout = function(){
208                     _api.start();
209                     _api.setIndex( this.index );
210                 };
211             }
212             _api.start();
213         }
214 
215         return this;
216     }
217 
218     var $ = function( selectors, context ){
219         return G( selectors, context );
220     }
221     window.$ = $;
222 })();
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM