zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    BZOJ 2821: 作诗(Poetize)( 分块 )
    BZOJ 2440: [中山市选2011]完全平方数( 二分答案 + 容斥原理 + 莫比乌斯函数 )
    BZOJ 1058: [ZJOI2007]报表统计( 链表 + set )
    BZOJ 1034: [ZJOI2008]泡泡堂BNB( 贪心 )
    BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )
    BZOJ 2329: [HNOI2011]括号修复( splay )
    BZOJ 3143: [Hnoi2013]游走( 高斯消元 )
    BZOJAC400题留念
    BZOJ 2982: combination( lucas )
    poj 3233
  • 原文地址:https://www.cnblogs.com/ghostwu/p/7715649.html
Copyright © 2011-2022 走看看