天猫购物网站最显眼的就是轮播图了。我在学习一样新js库,一个新框架或新的编程思想的时候,总是感叹“入门必做选项卡,进阶须撸轮播图。”作为一个React组件,它是状态操控行为的典型,拿来练手是个不错的选择。
为了复习,这次就尝试用原生的javascript+React来完成。


轮播图原生实现

所谓轮播图其实是扩展版的选项卡。

先布局

主干架构

<div id="tabs">
        <ul id="btns">
            <li><a href="javascript:;"></a></li>
            <li><a href="javascript:;"></a></li>
            <li><a href="javascript:;"></a></li>
            <li><a href="javascript:;"></a></li>
            <li><a href="javascript:;"></a></li>
            <li><a href="javascript:;"></a></li>
        </ul>
        <ul id="imgs">
            <li><img src="images/banner1.jpg"></li>
            <li><img src="images/banner2.jpg"></li>
            <li><img src="images/banner3.jpg"></li>
            <li><img src="images/banner4.jpg"></li>
            <li><img src="images/banner5.jpg"></li>
            <li><img src="images/banner6.jpg"></li>
        </ul>
  </div>

样式如下

/*css-reset*/
*{
  margin:0;
  padding: 0;
}
ul li{
  list-style: none;
}
img{
    border: none;
}
a{
  text-decoration: none;
}

/******************/
#tabs{
    width: 1130px;
    height: 500px;
    margin: 100px auto;
    position: relative;
    overflow: hidden;
}
#tabs li{
    float: left;
}
#tabs img{
    width: 1130px;
    height: 500px;
}
#btns{
    position: absolute;
    top:88%;
    left:395px;
    z-index: 9;
}
#btns a{
    display: block;
    width: 17px;
    height: 17px;
    background: rgba(0,0,0,0.3);
    border-radius: 50%;
    border: 2px solid rgba(0,0,0,0.3);
}
#btns li{
    margin: 10px;
}

大概效果

纯javascript实现

事件

一个简单的轮播图包括多个事件。

  • 鼠标移入移出:当鼠标移出,或者是鼠标不在轮播图上面,执行自动播放
  • 当鼠标移入:不再自动播放,而且点击按钮会执行跳转到相应的页面。

渐变

因为6张图不是很多。所以考虑六张图全部做绝对定位,按照顺序叠加在一起。然再通过一个透明度的运动框架,实现之。
在此我选用这个运动框架:

function getStyle(obj,attr){
    if(obj.crrentStyle){
        return obj.currentStyle[attr];
        //兼容IE8以下
    }else{
        return getComputedStyle(obj,false)[attr];
        //参数false已废。照用就好
    }
}

function startMove(obj,json,fn){
    //清理定时器
    if(obj.timer){
        clearInterval(obj.timer);
    }
    obj.timer=setInterval(function(){
        var bStop=false;//如果为false就停了定时器!
        var iCur=0;
        // 处理属性值
        for(var attr in json){
            if(attr=='opacity'){
                iCur=parseInt(parseFloat(getStyle(obj,attr))*100);
            }else{
                iCur=parseInt(getStyle(obj,attr));
            }
            //定义速度值
            var iSpeed=(json[attr]-iCur)/8;
            iSpeed=iSpeed>0?Math.ceil(iSpeed):Math.floor(iSpeed);
            //检测停止:如果我发现某个值不等于目标点bStop就不能为true。
            if(iCur!==json[attr]){
                bStop=false;
            }
            if(attr=='opacity'){
                obj.style[attr]=(iCur+iSpeed)/100;
                obj.style.filter='alpha(opacity:'+(iCur+iSpeed)+')';
            }else{
                obj.style[attr]=iCur+iSpeed+'px';
            }
        }
        //检测是否停止,是的话关掉定时器
        if(bStop===true){
            if(iCur==json[attr]){
                clearInterval(obj.timer);
                if(fn){
                    fn();
                }
            }
        }
    },30);
}

这个框架可以指定样式值进行渐变。

不得不说,这确实是一个很棒的运动框架。可以把它单独放在为一个名为move.js的文件中再引入。

根据这个思路写出原生的代码:

window.onload=function(){
    var oTab=document.getElementById('tabs');
    var oBtns=document.getElementById('btns');
    var aBtns=document.getElementsByTagName('a');
    var oImgs=document.getElementById('imgs');
    var aImgsLi=oImgs.getElementsByTagName('li');
    var bCheck=true;
    var iNow=0;

    // 以下是初始化设置:
    aBtns[0].style.background='rgba(255,255,255,0.5)';
    aImgsLi[0].style.zIndex=6;


    function iNowlistener(){//改变的核心函数
        // 初始化
        for(var i=0;i<aBtns.length;i++){
            aBtns[i].style.background='rgba(0,0,0,0.3)';
        }
        aBtns[iNow].style.background='rgba(255,255,255,0.5)';
        for(var j=0;j<aBtns.length;j++){
            aImgsLi[j].style.opacity=0;
            if(j!==iNow){
                aImgsLi[j].style.display='none';
            }else{
                aImgsLi[j].style.display='block';
                startMove(aImgsLi[j],{'opacity':100});
            }
        }
    }


    var timer=null;
    timer=setInterval(function(){
        if(bCheck){
            if(iNow==5){//将最后一个变为0
                iNow=0;
            }else{
                iNow++;
            }
            iNowlistener();
        }else{
            return false;
        }
    },2000);


    oTab.onmouseover=function(){
        bCheck=false;
        for(var i=0;i<aBtns.length;i++){
            aBtns[i].index=i;
            aBtns[i].onmouseover=function(){
                if(this.index==iNow){
                    return false;
                }else{
                    iNow=this.index;
                    iNowlistener();
                }
            };
        }

    };

    oTab.onmouseout=function(){
        bCheck=true;
    };

};

效果如下:

不得不说,原生的代码写起来好长好长。

很长吗?后面的更长。


React思路

以上原生代码已经经过了初步的封装——比如INowListener。但是在React的价值观来说,显然还需要进一步的封装。甚至重新拆分。最理想的情况是:顶层组件作为主干架构和状态机。下层组件接收状态并运行方法。

多少个组件?

在这个轮播图中,就三个组件。

- Tabs
   -imgs
   -btns
var Tabs=React.createClass({
            render:function(){

                return (
                    <div id="tabs">
                        <Btns/>
                        <Imgs/>
                    </div>
                );
            }
        });

        var Btns=React.createClass({
            render:function(){
                var arr=[];
                for(var i=0;i<6;i++){
                    var btnContent=
                      <li key={i.toString()}><a href="javascript:;"></a></li>
                    arr.push(btnContent);
                }
                return (
                    <ul id="btns">{arr}</ul>
                )
            }
        });

        var Imgs=React.createClass({
            render:function(){
                var arr=[];
                for(var i=0;i<6;i++){
                    var imgContent=
                      <li key={i.toString()}><img src={"images/banner"+(i+1)+".jpg"}/></li>
                    arr.push(imgContent);
                    console.log(arr)
                }
                return (
                    <ul id="imgs">{arr}</ul>
                );
            }
        });

        ReactDOM.render(
            <Tabs/>,
            document.getElementById('example')
        )

这样写就把样式写出来了。

哪个是状态?

iNOW是状态。而且是最重要的状态!既然这样,就考虑把状态iNow放顶层。

鼠标悬停看起来也是状态,但悬停按钮上,触发iNow改变——因此还是iNow。

鼠标移入移出事件,应该是状态。但是这个移入移出的状态依赖于iNow。所以不能单独用。

需要哪些props?

构造组件时,为了灵活性,一般都不考虑把组件框架写死。比如图片张数,id名,等等都应该是props。但是这些暂时来说,都是次要的。

状态肯定是一个核心props,此外,底层设置状态的回调也是核心的props之一。

空谈太多无意义,接下来尝试实现!


自动按钮

现在先不考虑其它,单看按钮。
在插入文档之后,开启一个定时器,每隔2000ms执行一次状态更新。

setState的写法

那涉及到了iNow状态根据前一个状态更新,官方文档不建议这种写法:

this.setState({
    return {
        iNow:this.state.iNow+1
    }
})

因为状态更新可能是异步的。这样写很容易出问题。
事实上,官网提供了这样的写法:

this.setState(function(prev,props){
    return {
        iNow:prev.iNow+1
    }
})

在这里只用第一个参数就够了。

想当然的按钮

定时器应该是一个状态计算器。

所以按钮可以这么写:

var Btns=React.createClass({
            getInitialState:function(){
                return ({
                    iNow:0
                })
            },
            componentDidMount:function(){
                var _this=this;
                setInterval(function(){
                    _this.setState(function(prev){
                        //console.log(prev)
                        if(prev.iNow==5){
                            return {
                                iNow:0
                            };
                        }else{
                            return {
                                iNow:prev.iNow+1
                            };
                        }
                    })
                },2000);
            },
            render:function(){
                var arr=[];
                for(var i=0;i<6;i++){
                    var btnContent=null;
                    if(i==this.state.iNow){
                        btnContent=
                          <li key={i.toString()}><a style={{background:'rgba(255,255,255,0.5)'}} href="javascript:;"></a></li>
                    }else{
                        btnContent=
                          <li key={i.toString()}><a href="javascript:;"></a></li>
                    }

                    arr.push(btnContent);
                }
                
                return (
                    <ul id="btns">{arr}</ul>
                );
            }
        });

按钮就实现了。
看起来不错,但是这样写可能在未来造成极大的不便。

悬停交互

再强调一次价值观这个概念,按照React的价值观,状态应该从顶层传下去,况且在这个案例中,顶层Tabs组件做一件事就够了:状态机,在Btn组件插入到文档之后,打开这个定时器。底层组件比如Btns根据状态每隔2000ms通过props刷新变化。

同时,我还要实现一个简单的交互功能:当鼠标悬停在Tabs上时,不再允许iNow自动更新。——可以做一个bCheck开关,当Tabs组件鼠标移入/移出时,触发bCheck的来回变化。

此处可能有个小问题,就是鼠标一道按钮组上时,会造成bCheck抖动。但是最后又变回false。所以认为不影响。

很自然想到,bCheck为false时,关闭定时器。但是这样做又等于浪费了定时器的功能,回调方法中一旦关掉定时器,再重新定时器就不是一般的麻烦了,为什么不直接在定时器做判断呢?所以我认为不应该让定时器停下来。只需要改变定时器计算iNow的行为就行了。

var Tabs=React.createClass({
            getInitialState:function(){
                return {
                    iNow:0,
                    bCheck:true//为false时不允许定时器计算更新iNow
                }
            },
            setInow:function(){
            var _this=this;
            var timer=setInterval(function(){
                  if(_this.state.bCheck){
                      //console.log(_this.state.bCheck)
                      _this.setState(function(prev){
                          if(prev.iNow==5){
                              return {
                                  iNow:0
                              };
                          }else{
                              return {
                                  iNow:prev.iNow+1
                              };
                          }
                      });
                  }else{
                      console.log('该停了!')
                      return false;
                  }

              },2000);

          },
            checkSwitch:function(){
                this.setState(function(prev){
                    return {
                        bCheck:!prev.bCheck,
                    }
                })
            },
            render:function(){
                return (
                    <div id="tabs" onMouseOver={this.checkSwitch} onMouseOut={this.checkSwitch}>
                        <Btns iNow={this.state.iNow} setInow={this.setInow}/>
                        <Imgs/>
                    </div>
                );
            }
        });

        var Btns=React.createClass({
            componentDidMount:function(){
                this.props.setInow();//插入后就执行回调方法
            },
            render:function(){
                var arr=[];
                for(var i=0;i<6;i++){
                    var btnContent=null;
                    if(i==this.props.iNow){
                        btnContent=
                          <li key={i.toString()}>
                          <a style={{background:'rgba(255,255,255,0.5)'}} href="javascript:;"></a>
                          </li>
                    }else{
                        btnContent=
                          <li key={i.toString()}><a href="javascript:;"></a></li>
                    }

                    arr.push(btnContent);
                }

                return (
                    <ul id="btns">{arr}</ul>
                );
            }
        });

图片动画

一件事三个步骤

图片组件虽说只是做一件事情(根据iNow渲染效果),但是也得分三步来做。

  • 首先,渲染前应该保证索引值非iNow的所有图片display为none。索引值为iNow的图片透明度为0。(初始化)

  • 其次,在首次插入文档完毕之后(componentDidMount),对第0张图执行startMove函数。

  • 第三,需要一个监听顶层iNow的方法。定时器已经给Btns组件用了,再用就会出错。

    留意到Imgs组件实际上只接受一个会变化的props那就是iNow。因此采用componentWillReceiveProps

生命周期方法

componentWillReceiveProps

组件接收到新的props时调用,并将其作为参数nextProps使用,此时可以更改组件propsstate

    componentWillReceiveProps: function(nextProps) {
        if (nextProps.bool) {
            this.setState({
                bool: true
            });
        }
    }

这里采用的两个组件周期方法都是组件真实存在时的方法。所以可以直接使用真实的DOM命令。

实现

var Tabs=React.createClass({
        getInitialState:function(){
            return {
                iNow:0,
                bCheck:true
            };
        },
        setInow:function(){
            var _this=this;
            var timer=setInterval(function(){
                if(_this.state.bCheck){
                    //console.log(_this.state.bCheck)
                    _this.setState(function(prev){
                        if(prev.iNow==5){
                            return {
                                iNow:0
                            };
                        }else{
                            return {
                                iNow:prev.iNow+1
                            };
                        }
                    });
                }else{
                    console.log('该停了!')
                    return false;
                }

            },2000);

        },
        checkSwitch:function(){
            console.log(this.state.bCheck)
            this.setState(function(prev){
                return {
                    bCheck:!prev.bCheck
                };
            });
        },
        render:function(){
            return (
                <div id="tabs"
                  onMouseOver={this.checkSwitch}
                  onMouseOut={this.checkSwitch}>
                    <Btns iNow={this.state.iNow}
                      setInow={this.setInow} />
                    <Imgs iNow={this.state.iNow}/>
                </div>
            );
        }
    });

    var Btns=React.createClass({
        componentDidMount:function(){
            this.props.setInow();
        },

        render:function(){
            var arr=[];
            for(var i=0;i<6;i++){
                var btnsContent=null;
                if(i==this.props.iNow){
                    btnsContent=
                        <li key={i.toString()}>
                            <a style={{background:'rgba(255,255,255,0.5)'}} href="javascript:;"></a>
                        </li>
                }else{
                    btnsContent=
                        <li key={i.toString()}>
                            <a href="javascript:;"></a>
                        </li>
                }
                arr.push(btnsContent);
            }

            return (
                <ul id="btns">{arr}</ul>
            );
        }
    });

    var Imgs=React.createClass({
        componentDidMount:function(){//刚开始加载时,就执行动画函数
            var iNow=this.props.iNow;
            var obj=document.getElementById('imgs').getElementsByTagName('li')[iNow].childNodes[0];
            startMove(obj,{'opacity':100});
        },
        componentWillReceiveProps:function(nextProps){
            var obj=document.getElementById('imgs').getElementsByTagName('li')[nextProps.iNow].childNodes[0];
            //console.log(obj)
            startMove(obj,{'opacity':100});
        },
        // this.startMove:startMove(),
        render:function(){
            var arr=[];
            for(var i=0;i<6;i++){
                var imgsContent=null
                if(i==this.props.iNow){
                    imgsContent=
                        <li key={i.toString()}>
                            <img style={{opacity:'0'}} src={'images/banner'+(i+1)+'.jpg'} />
                        </li>
                    arr.push(imgsContent);
                }else{
                    imgsContent=
                        <li key={i.toString()}>
                            <img style={{display:'none'}} src={'images/banner'+(i+1)+'.jpg'} />
                        </li>
                    arr.push(imgsContent);
                }

            }

            return (
                <ul id="imgs">{arr}</ul>
            )
        }
    })

    ReactDOM.render(
        <Tabs/>,
        document.getElementById('example')
    );

看起来Imgs组件已经很完备了。——就它的功能来说已经没有什么需要添加了。


鼠标悬停改变iNow

这个事件只能在底层组件Btns上实现。所以要拿到悬停的索引值。

然后通过回调,把该按钮的索引值设置为整个组件Tabs的状态iNow。

为了干这两件事,还是用一个changeInow(e)函数来包装它们。

给谁绑定?加什么事件?

为了忠实原来的代码。我给a标签加onMouseOver事件。

加了事件直接,秉承这React的核心价值观(一个组件只干一件事),我把get到的index值通过this.props.setInow传递回去。只要顶层的iNow变了,下面的组件不管什么状态,都会乖乖听话了。

如何获取当前悬停的索引值?

在Jquery很容易使用index方法来获取索引值。但是在原生方法中,还得费一番周章。

给所有a绑定一个onMouseOver事件,假设该事件方法的参数为e,那么e.target就是该参数的方法。

这需要写一个getIndex方法

...
getIndex:function(e){
  var list=e.target.parentNode.parentNode.childNodes;
  for(var i=0;i<list.length;i++){
    if(list[i]===e.target.parentNode){
      return  i;
    }
  }
},
...

拿到索引值之后

——就把它设置为顶层的iNow。

既然决定通过this.props.setInow回调,那么还得传一个索引值参数,回到顶层稍微修改下方法,就实现了。

全部代码:

var Tabs=React.createClass({//顶层组件
        getInitialState:function(){
            return {
                iNow:0,
                bCheck:true
            };
        },
        setInow:function(index){//核心状态计算工具:依赖定时器进行实时刷新
            if(index!==undefined){//如果参数有内容。
                this.setState({
                    iNow:index
                });
            }else{
                var _this=this;
                this.timer=setInterval(function(){
                    if(_this.state.bCheck){
                        //console.log(_this.state.bCheck)
                        _this.setState(function(prev){
                            if(prev.iNow==5){
                                return {
                                    iNow:0
                                };
                            }else{
                                return {
                                    iNow:prev.iNow+1
                                };
                            }
                        });
                    }else{
                        //console.log('该停了!')
                        return false;
                    }
                },2000);
            }
        },
        checkSwitch:function(){
            //console.log(this.state.bCheck)
            this.setState(function(prev){
                return {
                    bCheck:!prev.bCheck
                };
            });
        },
        render:function(){
            return (
                <div id="tabs"
                  onMouseOver={this.checkSwitch}
                  onMouseOut={this.checkSwitch}>
                    <Btns iNow={this.state.iNow}
                      setInow={this.setInow} />
                    <Imgs iNow={this.state.iNow}/>
                </div>
            );
        }
    });

    var Btns=React.createClass({
        componentDidMount:function(){
            this.props.setInow();
        },
        getIndex:function(e){//获取a的父级索引值
            var list=e.target.parentNode.parentNode.childNodes;
            for(var i=0;i<list.length;i++){
                if(list[i]===e.target.parentNode){
                    return i;
                }
            }
        },
        changeInow:function(e){//回调方法
            //console.log($(e.target).parent().index());
            //console.log(this.getIndex(e));
            var index=this.getIndex(e);
            this.props.setInow(index)
        },

        render:function(){
            var arr=[];
            for(var i=0;i<6;i++){
                var btnsContent=null;
                var index=i;
                if(i==this.props.iNow){
                    btnsContent=
                        <li key={i.toString()}>
                            <a onMouseOver={this.changeInow} style={{background:'rgba(255,255,255,0.5)'}} href="javascript:;"></a>
                        </li>
                }else{
                    btnsContent=
                        <li key={i.toString()}>
                            <a  onMouseOver={this.changeInow} href="javascript:;"></a>
                        </li>
                }
                arr.push(btnsContent);
            }

            return (
                <ul id="btns">{arr}</ul>
            );
        }
    });

    var Imgs=React.createClass({
        componentDidMount:function(){//刚开始加载时,就执行动画函数
            var iNow=this.props.iNow;
            var obj=document.getElementById('imgs').getElementsByTagName('li')[iNow].childNodes[0];
            startMove(obj,{'opacity':100});
        },
        componentWillReceiveProps:function(nextProps){
            var obj=document.getElementById('imgs').getElementsByTagName('li')[nextProps.iNow].childNodes[0];
            //console.log(obj)
            startMove(obj,{'opacity':100});
        },
        // this.startMove:startMove(),
        render:function(){
            var arr=[];
            for(var i=0;i<6;i++){
                var imgsContent=null
                if(i==this.props.iNow){
                    imgsContent=
                        <li key={i.toString()}>
                            <img style={{opacity:'0'}} src={'images/banner'+(i+1)+'.jpg'} />
                        </li>
                    arr.push(imgsContent);
                }else{
                    imgsContent=
                        <li key={i.toString()}>
                            <img style={{display:'none'}} src={'images/banner'+(i+1)+'.jpg'} />
                        </li>
                    arr.push(imgsContent);
                }

            }

            return (
                <ul id="imgs">{arr}</ul>
            )
        }
    })

    ReactDOM.render(
        <Tabs/>,
        document.getElementById('example')
    );

完善

我们要让这个组件可复用,换言之就是把之前写死的东西比如图片数量,样式,id名都变成Tabs的props属性。

这下工作量够了吧。原来50多行的东西改写完之后大概150多行。

var Tabs=React.createClass({//顶层组件
        getInitialState:function(){
            return {
                iNow:0,
                bCheck:true
            };
        },
        setInow:function(index){//核心状态计算工具:依赖定时器进行实时刷新
            if(index!==undefined){//如果参数有内容。
                this.setState({
                    iNow:index
                });
            }else{
                var _this=this;
                this.timer=setInterval(function(){
                    if(_this.state.bCheck){
                        //console.log(_this.state.bCheck)
                        _this.setState(function(prev){
                            if(prev.iNow==this.props.nums-1){
                                return {
                                    iNow:0
                                };
                            }else{
                                return {
                                    iNow:prev.iNow+1
                                };
                            }
                        });
                    }else{
                        //console.log('该停了!')
                        return false;
                    }
                },this.props.timer);
            }
        },
        checkSwitch:function(){
            //console.log(this.state.bCheck)
            this.setState(function(prev){
                return {
                    bCheck:!prev.bCheck
                };
            });
        },
        render:function(){
            return (
                <div id={this.props.idNames.main}
                  onMouseOver={this.checkSwitch}
                  onMouseOut={this.checkSwitch}>

                    <Btns iNow={this.state.iNow}
                      setInow={this.setInow}
                      nums={this.props.nums}
                      idNames={this.props.idNames} />

                    <Imgs iNow={this.state.iNow}
                    nums={this.props.nums}
                    idNames={this.props.idNames}
                    imgType={this.props.imgType} />

                </div>
            );
        }
    });

    var Btns=React.createClass({
        componentDidMount:function(){
            this.props.setInow();
        },
        getIndex:function(e){//获取a的父级索引值
            var list=e.target.parentNode.parentNode.childNodes;
            for(var i=0;i<list.length;i++){
                if(list[i]===e.target.parentNode){
                    return i;
                }
            }
        },
        changeInow:function(e){//回调方法
            //console.log($(e.target).parent().index());
            //console.log(this.getIndex(e));
            var index=this.getIndex(e);
            this.props.setInow(index)
        },

        render:function(){
            var arr=[];
            for(var i=0;i<this.props.nums;i++){
                var btnsContent=null;
                var index=i;
                if(i==this.props.iNow){
                    btnsContent=
                        <li key={i.toString()}>
                            <a onMouseOver={this.changeInow} id={this.props.idNames.active} href="javascript:;"></a>
                        </li>
                }else{
                    btnsContent=
                        <li key={i.toString()}>
                            <a  onMouseOver={this.changeInow} href="javascript:;"></a>
                        </li>
                }
                arr.push(btnsContent);
            }

            return (
                <ul id={this.props.idNames.btns}>{arr}</ul>
            );
        }
    });

    var Imgs=React.createClass({
        componentDidMount:function(){//刚开始加载时,就执行动画函数
            var iNow=this.props.iNow;
            var obj=document.getElementById(this.props.idNames.imgs).getElementsByTagName('li')[iNow].childNodes[0];
            startMove(obj,{'opacity':100});
        },
        componentWillReceiveProps:function(nextProps){//每当收到新的props就执行动画
            var obj=document.getElementById(this.props.idNames.imgs).getElementsByTagName('li')[nextProps.iNow].childNodes[0];
            //console.log(obj)
            startMove(obj,{'opacity':100});
        },

        render:function(){
            var arr=[];
            for(var i=0;i<this.props.nums;i++){
                var imgsContent=null;
                var src=this.props.imgType.url+this.props.imgType.name+(i+1)+'.'+this.props.imgType.type;
                if(i==this.props.iNow){
                    imgsContent=
                        <li key={i.toString()}>
                            <img style={{opacity:'0'}} src={src} />
                        </li>
                    arr.push(imgsContent);
                }else{
                    imgsContent=
                        <li key={i.toString()}>
                            <img style={{display:'none'}} src={src} />
                        </li>
                    arr.push(imgsContent);
                }
            }

            return (
                <ul id={this.props.idNames.imgs}>{arr}</ul>
            )
        }
    })

    ReactDOM.render(
        <Tabs
          nums={6}
          timer={2000}
          idNames={
              {
                  main:"tabs",
                  btns:"btns",
                  imgs:"imgs",
                  active:"btn-active"
              }
          }
          imgType={
              {
                  type:"jpg",
                  url:"images/",
                  name:"banner"
              }
          }
           />,
        document.getElementById('example')
    );

其中多设置了一个#btn-active样式。

#btn-active{
    background:rgba(255,255,255,0.5)!important;
}

是不是好长好长呢?

demo地址:

http://djtao.top/tabs/

但是这个确实是一个可复用的,而且还是原生js写成的组件。

不得不说,作为一个初学几天的人,写这东西时的时候遭遇好多的坑。但是最后“蓦然回首,那人却在灯火阑珊处”,也有种人生三境界的感悟了!

 posted on 2016-12-20 22:36  葡萄美酒夜光杯  阅读(5766)  评论(14编辑  收藏  举报