React.js实现轮播图

react.js的基本思想,是通过改变state或props的值,重新渲染用户界面(不用操作DOM)。截图GIF效果如下(只截取了三页效果):


GIF1.gif
1.文件列表:
1490606951(1).jpg
2.组件功能说明:

1.可控制滚动方向(上下左右)
2.可控制轮播图片的宽高
3.可控制轮播图片的数量
4.可控制轮播图片停留时间
5.可控制轮播的风格
6.轮播的基本功能(dots,左右按钮,鼠标滑入滑出的暂停与播放,无缝)

3.组件使用说明:

用户修改json中的数据即可使用,

  • imgArray ---------------------------- 数组类型,放置轮播图片的地址(必填)
  • linkArray ---------------------------- 数组类型,放置点击图片访问的地址(必填)
  • lunboObject ------------------------ json类型,放置一些轮播图的基本设置(必填)
    • interval ---------------------------- number类型,设置图片停留时间
    • direction -------------------------- string类型,设置运动的方向
    • number --------------------------- number类型,设置图片数量(必填)
    • boxStyle -------------------------- string类型,设置某些地方的样式
    • imgWidth ------------------------- number类型,设置图片宽度(必填)
    • imgHeight ------------------------ number类型,设置图片高度(必填)
4.组件内容:

1.data.json

    "imgArray": [
        "../src/pages/lunbo/img/1.jpg",
        "../src/pages/lunbo/img/2.jpg",
        "../src/pages/lunbo/img/3.jpg",
        "../src/pages/lunbo/img/4.jpg",
        "../src/pages/lunbo/img/5.jpg",
        "../src/pages/lunbo/img/6.jpg",
        "../src/pages/lunbo/img/7.jpg"
    ],
    "linkArray": [
        "http://bj.ganji.com",
        "http://bj.ganji.com",
        "http://bj.ganji.com",
        "http://bj.ganji.com",
        "http://bj.ganji.com",
        "http://bj.ganji.com",
        "http://bj.ganji.com"
    ],
    "lunboObject": {
        "interval": 1000,
        "direction": "right",
        "number": 7,
        "boxStyle": "content",
        "imgWidth": 550,
        "imgHeight": 350
    }
}

2.lunbo.jsx

var style = require('./lunbo.less');
var ReactDOM = require('react-dom');
var React = require('react');
var data = require('./data.json');

var LunBoControl = React.createClass({
    /*对出入的props进行验证*/
    propsTypes : {
        defaultActiveIndex:React.PropTypes.number,
        interval:React.PropTypes.number,
        direction:React.PropTypes.oneOf['right','left','top','bottom'],
        number:React.PropTypes.number,
        boxStyle:React.PropTypes.string,
        imgWidth:React.PropTypes.number.isRequired,
        imgHeight:React.PropTypes.number.isRequired
    },
    /*设置默认的props值*/
    getDefaultProps: function(){
        return {
            direction:'right',
            interval: 1000,
            boxStyle:'content'
        };
    },
    /*初始化state值*/
    getInitialState : function(){
        return{
            activeIndex:1,
            offsetDistance:this.props.direction == 'right' || this.props.direction == 'left' ? -this.props.imgWidth : -this.props.imgHeight,
            pause:false,
            flag:true
        };
    },
    /*生命周期函数 在首次渲染之前*/
    componentWillMount : function(){
        this.direction = this.props.direction === 'left' || this.props.direction === 'right'? 'x' : 'y';
    },
    /*在真实的DOM被渲染出来后*/
    componentDidMount : function(){
        this.autoPlay();
    },
    /*组件被移除之前*/
    componentWillUnmount : function(){
        clearTimeout(this.timeOuter);
        clearInterval(this.timer);
    },
    autoPlay : function(){
        switch(this.props.direction){
        case 'right' : 
            this.timerOuter=setTimeout(this.playRight,this.props.interval);
            this.direction='x';
            break;
        case 'left'  : 
            this.timerOuter=setTimeout(this.playLeft,this.props.interval);
            this.direction='x';
            break;
        case 'top'   : 
            this.timerOuter=setTimeout(this.playLeft,this.props.interval);
            this.direction='y';
            break;
        case 'bottom': 
            this.timerOuter=setTimeout(this.playRight,this.props.interval);
            this.direction='y';
            break;
        };
    },
    /*对不同方向做的相应模板上样式的处理*/
    directionHandle : function(){
        if(this.direction === 'y'){
            return {top : this.state.offsetDistance+'px',width : this.props.imgWidth,height : this.props.imgHeight*(this.props.number+2)};
        }else {
            return {left : this.state.offsetDistance+'px',width : this.props.imgWidth*(this.props.number+2),height : this.props.imgHeight};
        }
    },
    /*鼠标滑入,滑出*/
    mouseHandle : function(e){
        if(e.type === 'mouseover'){
            this.setState({pause : true});
        }else if(e.type === 'mouseleave'){
            this.setState({pause : false});
            this.autoPlay();
        }
    },
    /*圆点显示效果*/
    checkDots : function(index){
        var activeIndex;
        if(this.state.activeIndex === this.props.number+1){
            activeIndex = 1;
        }else if(this.state.activeIndex === 0){
            activeIndex = this.props.number;
        }else {
            activeIndex = this.state.activeIndex;
        }
        return index+1 === activeIndex? 'dots active' : 'dots';
    },
    /*鼠标滑入圆点*/
    dotsHover : function(index){
        clearInterval(this.timer);
        this.setState({activeIndex:index+1});
        this.position();
    },
    /*向右或向下*/
    playRight: function(indexIn){
        if(this.state.flag){
            var index=indexIn?indexIn:this.state.activeIndex+1;
            this.setState({activeIndex:index});
            this.position();
        }
    },
    /*向左或向上*/
    playLeft: function(indexIn){
        if(this.state.flag){
            var index=indexIn?indexIn:this.state.activeIndex-1;
            this.setState({activeIndex:index});
            this.position();
        }
    },
    /*运动效果*/
    position: function(){
        this.setState({flag:false});
        this.timer = setInterval(function(){
            if(this.direction === 'x'){
                var boxDistance = this.props.imgWidth;
            }else {
                var boxDistance = this.props.imgHeight;
            }
            var offsetDistance = this.state.offsetDistance;
            if(Math.abs(offsetDistance-(-boxDistance*this.state.activeIndex)) <= 0.09){
                offsetDistance = -boxDistance*this.state.activeIndex;
                clearInterval(this.timer);
                this.setState({flag:true});
                if(this.state.activeIndex > this.props.number){
                    offsetDistance = -boxDistance;
                    this.setState({activeIndex : 1});
                }else if(this.state.activeIndex === 0){
                    offsetDistance = -boxDistance*this.props.number;
                    this.setState({activeIndex : this.props.number});
                }
                this.setState({offsetDistance:offsetDistance});
                if(!this.state.pause){
                    this.autoPlay();
                }
            }else{
                offsetDistance = offsetDistance-(boxDistance*this.state.activeIndex-Math.abs(offsetDistance))/30;
                this.setState({offsetDistance:offsetDistance});
            }
        }.bind(this),10);
    },
    /*点击向左按钮*/
    left: function(){
        var oldIndex=this.state.activeIndex;
        this.playLeft(oldIndex-1);
    },
    /*点击向右按钮*/
    right: function(){
        var oldIndex=this.state.activeIndex;
        this.playRight(oldIndex+1);
    },
    render : function(){
        var _this = this;
        return (<div className={this.props.boxStyle} style={{width:this.props.imgWidth, height:this.props.imgHeight}} onMouseOver={this.mouseHandle} onMouseLeave={this.mouseHandle}>
            <span className="leftIcon" onClick={this.left}></span>
            <span className="rightIcon" onClick={this.right}></span>
            <div className="dots-wrap">
                {   
                    React.Children.map(this.props.children,function(elem,index){
                        return (<span className={_this.checkDots(index)} onMouseOver={_this.dotsHover.bind(_this,index)}></span>);
                    })
                }
            </div>
            <ul style={this.directionHandle()}>
                {this.props.children[this.props.number-1]}
                {this.props.children}
                {this.props.children[0]}
            </ul>
        </div>);
    }
});
var LunBoComponent = React.createClass({
    propsTypes : {
        lunboObject : React.PropTypes.object.isRequired,
        imgArray : React.PropTypes.array.isRequired,
        linkArray : React.PropTypes.array
    },
    render : function(){
        return (
                <LunBoControl interval={this.props.lunboObject.interval} number={this.props.lunboObject.number} boxStyle={this.props.lunboObject.boxStyle} imgWidth={this.props.lunboObject.imgWidth} imgHeight={this.props.lunboObject.imgHeight} direction={this.props.lunboObject.direction}>
                    {    
                        this.props.imgArray.map(function(item,index){
                            return <li key={index}><a href={this.props.linkArray[index]}><img width={this.props.lunboObject.imgWidth} height={this.props.lunboObject.imgHeight} src={item}/></a></li>;
                        }.bind(this))
                    }
                </LunBoControl>
        );
    }
});
module.exports = LunBoComponent;
/*引用按以下方式*/
var LunBoComponent = require('./lunbo.jsx');
ReactDOM.render(<LunBoComponent lunboObject={data.lunboObject} imgArray={data.imgArray} linkArray={data.linkArray}/>, document.getElementById('wrapper'));

3.lunbo.less

li {
    float: left;
    margin: 0;
    padding: 0;
    font-size: 12px;
}
img {
    vertical-align: top;
}
#wrapper > div {
    overflow: hidden;
    position: relative;
    margin: 0 auto;
    margin-top: 50px;
}
ul {
    margin: 0;
    padding: 0;
    list-style: none;
    position: relative;
}
.lunbo-item {
    float: left;
}
.leftIcon {
    position: absolute;
    display: inline-block;
    width: 25px;
    height: 25px;
    transform: rotate(-45deg);
    top: 162px;
    left: 10px;
    border-top: 3px solid #00ffcc;
    border-left: 3px solid #00ffcc;
    z-index: 999;
    text-indent: -100%;
    cursor: pointer;
}
.rightIcon {
    position: absolute;
    display: inline-block;
    width: 25px;
    height: 25px;
    transform: rotate(45deg);
    top: 162px;
    right: 10px;
    border-right: 3px solid #00ffcc;
    border-top: 3px solid #00ffcc;
    z-index: 999;
    text-indent: -100%;
    cursor: pointer;
}
.dots {
    display: inline-block;
    width: 16px;
    height: 16px;
    background: #eee;
    border-radius: 8px;
    margin-right: 8px;
    float: left;
    cursor: pointer;
}
.dots.active {
    background: #000;
}
.dots-wrap {
    overflow: hidden;
    position: absolute;
    z-index: 99;
    bottom: 10px;
    right: 20px;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,563评论 18 139
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,982评论 4 60
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,266评论 25 707
  • 为什么今天把主题定为开心的笑,原因是我每天都能看到大家分享的意想不到,看完之后都会有很大的收获。我越来越觉...
    调整心态阅读 249评论 0 0
  • 【0629晨读】 今天分享的书是《让创意更有黏性》。 本书介绍打造创意的方法,能让你的观点直抵人心,进而改变他人的...
    顾尘埃阅读 114评论 4 2