一个简单的轮播

为了更具有通用和参考性,轮播组件中,轮播只使用了react,没有添加其他的状态管理,或者参数类型限制的库. 所以这个轮播的方法,同样可以用于vue 等其他框架
github地址

最终效果

显示无限循环原理

如图所示,如果轮播里面有三个部分,那么可以在首端前添加一个跟最后一块一样的dom节点,同理在最末端添加跟首端相同的节点,这样当轮播到末端,在下一张的情况下,就可以无缝衔接首端的节点,然后当动画结束后,在直接切换到真正的首端,就实现了无缝衔接的轮播器

组件代码
import React, {Component} from 'react'; 
import style from './style.use.less'; 
 
export default class Test extends Component { 
    static defaultProps = { 
        step: 2000, 
        animationStep: 1 
    } 
 
    constructor(props) { 
        super(props) 
        this.state = { 
            currentCarousel: 0, 
            translateList: [], 
            animationStep: 0, 
        } 
 
        this.handleCarouselBodyMouseOver = this.handleCarouselBodyMouseOver.bind(this); 
        this.handleCarouselBodyMouseOut = this.handleCarouselBodyMouseOut.bind(this); 
        this.handleCarouselFooterMouseOver = this.handleCarouselFooterMouseOver.bind(this); 
        this.renderIndicators = this.renderIndicators.bind(this); 
        this.getIndicatorsActive = this.getIndicatorsActive.bind(this); 
        this.handlerNext = this.handlerNext.bind(this); 
        this.handlerTransitionEnd = this.handlerTransitionEnd.bind(this); 
        this.handlerPre = this.handlerPre.bind(this); 
    } 
 
    componentWillMount() { 
        style.use() 
    } 
 
    componentWillUnmount() { 
        style.unuse() 
        this.stopCarousel() 
    } 
 
    componentDidMount() { 
        this.setState({ 
            animationStep: this.props.animationStep 
        }) 
        this.startCarousel() 
         
    } 
 
    /** 
     * @description 开始轮播 
     */ 
    startCarousel() { 
        this.stopCarousel() 
        this.timerID = setInterval(() => { 
                this.handlerCarousel()   
            }, 
            this.props.step 
        ); 
    } 
 
    /** 
     * @description 更改当前循环到的轮播下标 
     * @param {String} type 运动的方向类型 
     */ 
    handlerCarousel(type) { 
        let direction = 1; 
        if (type === 'left') {  // 向做运动 下标减1 
            direction = -1; 
        } 
 
        if (this.state.currentCarousel % (this.props.children.length + 1) !== this.props.children.length && this.state.currentCarousel >= 0) { // 下标不为-1 或者最后一项的情况下正常 递增或者递减 
            this.setState(pre => { 
                pre.currentCarousel += direction; 
                return { 
                    animationStep: this.props.animationStep, // 运动动画 设置值  因为 当坐标在边界的时候 会取消动画时间 所以在不为边界的时候 要恢复动画时间 不然切换无轮播动画 
                    currentCarousel: pre.currentCarousel % (this.props.children.length + 1) 
                } 
            }) 
        } 
         
    } 
 
    /** 
     * @description 监听动画结束 在下标为边界时 并且切换的动画结束 取消动画 并调整轮播位置 
     */ 
    handlerTransitionEnd() { 
        // 当在最末端的时候 取消动画 并将坐标重制为0 
        if (this.state.currentCarousel % (this.props.children.length + 1) === this.props.children.length) { 
            this.setState(pre => { 
                return { 
                    animationStep: 0, 
                    currentCarousel: 0, 
                } 
            }) 
        }  
        // 当在最前端的时候 取消动画 并将坐标重制为最大 
        else if (this.state.currentCarousel < 0) { 
            this.setState(pre => { 
                return { 
                    animationStep: 0, 
                    currentCarousel: this.props.children.length - 1, 
                } 
            }) 
        } 
    } 
 
    /** 
     * @description  停止轮播 
     */ 
    stopCarousel() { 
        clearInterval(this.timerID); 
    } 
 
 
    /** 
     * @description 指示按钮的mouseover事件 
     */ 
    handleCarouselFooterMouseOver(currentIndex) { 
        this.setState({ 
            animationStep: this.props.animationStep, 
            currentCarousel: currentIndex 
        }); 
    } 
 
    /** 
     * @description 轮播的mouseover事件 
     */ 
    handleCarouselBodyMouseOver() { 
        this.stopCarousel(); 
    } 
 
    /** 
     * @description 轮播的mouseout事件 
     */ 
    handleCarouselBodyMouseOut() { 
        this.startCarousel(); 
    } 
 
    /** 
     * @description 轮播的mouseout事件 
     */ 
    handlerNext() { 
        this.handlerCarousel('right'); 
    } 
 
    handlerPre() { 
        this.handlerCarousel('left'); 
    } 
 
    getIndicatorsActive(index) { 
        // 边界判断 使在轮播在边界的时候 导航下面的小标 也能正常的添加active状态 
        if (this.state.currentCarousel === index || this.state.currentCarousel === index + this.props.children.length || (this.state.currentCarousel < 0 && index === this.props.children.length - 1)) { 
            return 'active'; 
        } 
        return '' 
    } 
 
    /** 
     * @description 导航的指示按钮 
     */ 
    renderIndicators() { 
         
        return ( 
            <div className = 'carousel-footer'> 
                <ul className = 'indicators-container'> 
                    {this.props.children.map((item, index) => { 
                        let active = this.getIndicatorsActive(index) 
                        return <li onMouseOver = {() => this.handleCarouselFooterMouseOver(index)} className = {`indicators-item ${active}`} key = {index} ></li> 
                    })} 
                </ul> 
            </div> 
        ) 
    } 
 
    render() { 
        return(  
            <div className = 'carousel-container' onMouseOver = {this.handleCarouselBodyMouseOver} onMouseOut = {this.handleCarouselBodyMouseOut}> 
                <div className = 'carousel-body' onTransitionEnd = {this.handlerTransitionEnd} style = {{transition: `transform ${this.state.animationStep}s`,width: `${(this.props.children.length+2)*100}%`, transform: `translateX(${-100/(this.props.children.length+2)*(this.state.currentCarousel+1)}%)`}}> 
                    <div className = {`carousel-item`} style = {{width: `${100/(this.props.children.length+2)}%`}} key = {'strat'} >{this.props.children[this.props.children.length-1]}</div> 
                    {this.props.children.map((item, index) => { 
                        return <div className = {`carousel-item`} style = {{width: `${100/(this.props.children.length+2)}%`}} key = {index} >{item}</div> 
                    })} 
                     <div className = {`carousel-item`} style = {{width: `${100/(this.props.children.length+2)}%`}} key = {'end'} >{this.props.children[0]}</div> 
                </div> 
                {this.renderIndicators()} 
                <div className = 'btn-container'> 
                    <div className = 'btn-direction pre' onClick = {this.handlerPre}>{'<'}</div> 
                    <div className = 'btn-direction next' onClick = {this.handlerNext}>{'>'}</div>   
                </div> 
            </div> 
        ) 
    } 
} 
组件csss
.carousel-container { 
    position: relative; 
    width: 100%; 
    height: 100%; 
    overflow: hidden; 
    .carousel-body { 
        height: 100%; 
        .carousel-item { 
            display: inline-block; 
            width: 100%; 
            height: 100%; 
        } 
    } 
    .carousel-footer { 
        position: absolute; 
        width: 100%; 
        bottom: 0; 
 
        .indicators-container { 
            text-align: center; 
            padding: 0; 
            .indicators-item { 
                list-style: none; 
                display: inline-block; 
                opacity: .48; 
                width: 30px; 
                height: 2px; 
                background-color: #fff; 
                border: none; 
                outline: none; 
                padding: 0; 
                margin: 0; 
                cursor: pointer; 
                transition: .3s; 
                margin: 0 4px; 
 
                &.active { 
                    opacity: 1; 
                } 
            } 
        } 
    } 
 
    .btn-container { 
        position: absolute; 
        width: 100%; 
        top: 50%; 
        transform: translateY(-50%); 
         
        .btn-direction { 
            padding: 0; 
            margin: 0; 
            height: 42px; 
            line-height: 38px; 
            width: 36px; 
            cursor: pointer; 
            transition: .3s; 
            border-radius: 50%; 
            background-color: rgba(31,45,61,.11); 
            color: #fff; 
            top: 50%; 
            z-index: 10; 
            text-align: center; 
            font-size: 12px; 
            display: inline-block; 
            position: absolute; 
            top: 50%; 
            transform: translateY(-50%); 
            opacity: 0; 
            
        } 
 
        .pre { 
            left: 12px; 
        } 
 
        .next { 
            right: 12px; 
        } 
 
    } 
 
    
     
} 
.carousel-container:hover .btn-direction{ 
    opacity: 1; 
     
    &.pre { 
        left: 24px; 
    } 
 
    &.next { 
        right: 24px; 
    } 
} 
最终调用
import React, {Component} from 'react'; 
import style from './style.use.less' 
import Carouse from '../../components/Carousel/Carousel' 
 
export default class Test extends Component { 
    componentWillMount() { 
        style.use() 
    } 
 
    componentWillUnmount() { 
        style.unuse() 
    } 
 
    render() { 
        return (  
            <div className = 'carouse'>    
                <Carouse> 
                    <div className = 'box'>1</div> 
                    <div className = 'box'>2</div> 
                    <div className = 'box'>3</div> 
                    <div className = 'box'>4</div> 
                </Carouse> 
            </div> 
             
        ) 
    } 
} 

评论关闭
IT干货网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

手写一个react日历超级简单