• React视角下的轮播图


    天猫购物网站最显眼的就是轮播图了。我在学习一样新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{
         1130px;
        height: 500px;
        margin: 100px auto;
        position: relative;
        overflow: hidden;
    }
    #tabs li{
        float: left;
    }
    #tabs img{
         1130px;
        height: 500px;
    }
    #btns{
        position: absolute;
        top:88%;
        left:395px;
        z-index: 9;
    }
    #btns a{
        display: block;
         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写成的组件。

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

  • 相关阅读:
    3组-Alpha冲刺-1/6
    3组 需求分析报告
    结对编程作业
    3组 团队展示
    8组-Alpha冲刺-1/6
    8组 需求分析报告
    刘凌斌 1.3
    结对编程作业
    8组 团队介绍与选题报告
    3组-Alpha冲刺-1/6
  • 原文地址:https://www.cnblogs.com/djtao/p/6204641.html
Copyright © 2020-2023  润新知