继上一篇随笔,优化3张以上图片轮播React组件

import React from 'react';
import PropTypes from 'prop-types';

import {getSwipeWay} from '../utils/swipe';

//imgs         : 图片src数组
//playTime  : 轮播下一张图片的时间间隔
//notAuto   : 是否开启自动轮播 默认开启 false

const PropsChecker = {
    imgs      : PropTypes.array.isRequired,
    playTime : PropTypes.number,
    notAuto  : PropTypes.bool,    
};

class Carousel extends React.Component {
    static defaultProps = {
        playTime : 5000,
        notAuto  : false,
    }
    
    constructor(args){
        super(args);
        this.state = {
        };
        //缓存各个currIndex的ul之后的标签
        this.storeElements = {};
        //判断滑动手势
        this.swipeWay = getSwipeWay(50);//闸值50
        //图片显示的限制
        this.limit = 3;
        //当前展示的图片
        this.currIndex = 0;
        //展示的数组
        this.showImgs = [];
        //手势滑动坐标
        this.position = {
            x1:0,
            x2:0,
            y1:0,
            y2:0,
        };
        //<ul>
        this.Ul = null;
        //禁止在transiton的期间操作
        this.isTransition = false;
        //定时器
        this.timer = 0;
    }

    componentDidMount(){
        this.autoPlay();
    }

    componentWillUnmount(){
        clearTimeout(this.timer);
    }

    getHead(arr){
        if(Array.isArray(arr)){
            return arr[0];
        }
        console.error('非数组');
    }

    getLast(arr){
        if(Array.isArray(arr)){
            const len = arr.length;
            return arr[len-1];            
        }
        console.error('非数组');
    }

    calcIndex(){
        const {imgs}     = this.props;
        const len          = imgs.length;
        const limit     = this.limit;
        const currIndex = this.currIndex;

        if(currIndex == 0){
            this.showImgs = imgs.slice(0,limit - 1);
            this.showImgs.unshift(this.getLast(imgs));
            return;
        }

        if(currIndex == len - 1){
            this.showImgs = imgs.slice(len -2 ,len);
            this.showImgs.push(this.getHead(imgs));
            return;
        }

        this.showImgs = imgs.slice(currIndex -1 , currIndex + limit -1);

    }

    changeCurrIndex(flag){
        const {imgs} = this.props;
        const last    = imgs.length -1;
        const currIndex = this.currIndex;
        if(flag === '-'){
            this.currIndex = currIndex == 0 ? last : currIndex -1 ;
            return;
        }

        if(flag === '+'){
            this.currIndex = currIndex == last ? 0 : currIndex + 1 ;
            return;
        }
    }

    ulTranslate(value){
        const Ul = this.Ul;
        if(Ul){

            if(Ul.style.webkitTranslate ){
                Ul.style.webkitTranslate = value;
            }else{
                Ul.style.translate = value;
            }

        }

    }

    createUl(){
        const currIndex     = this.currIndex;
        const storeElements = this.storeElements;

        //缓存这些标签,避免多次创建,很有必要
        if(!storeElements[currIndex]){
            //要保证<ul>key不同 也就是每次轮播后都要是新的标签,有损性能
            const Ul = (<ul onTouchEnd={this.touchEnd} 
                    onTouchMove={this.touchMove} 
                    onTouchStart={this.touchStart} 
                    onTransitionEnd={this.transitionEnd} ref={(ele)=>this.Ul=ele} key={currIndex}>

                    {this.createLis()}
                </ul>);

            storeElements[currIndex] = Ul;
        }

        return storeElements[currIndex];
    }

    createLis(){
        this.calcIndex();        
        const imgs = this.showImgs;

        return imgs.map((src,i)=>{
            const liStyle = {
                // translate:(-i)+'00%',
                translate:( (i+'00') - 100 ) + '%',
                WebkitTranslate:( (i+'00') - 100 ) + '%',
            };

            return <li className='item' key={i} style={liStyle} ><img src={src}  /></li>;
        });

    }

    touchStart = (e) => {
        if(this.isTransition){
            return;
        }

        clearTimeout(this.timer);

        const {clientX,clientY} = e.touches[0];
        this.position.x1 = clientX;
        this.position.y1 = clientY;
    }

    touchMove = (e) => {

    }

    touchEnd = (e) => {
        if(this.isTransition){
            return;
        }

        const {clientX,clientY} = e.changedTouches[0];
        this.position.x2 = clientX;
        this.position.y2 = clientY;

        const {x1,x2,y1,y2} = this.position;

        const direction = this.swipeWay(x1,x2,y1,y2);

        if( direction === 'Left'){
            this.changeCurrIndex('+');
            this.isTransition = true;
            this.ulTranslate('-100%');
        }

        if(direction === 'Right'){
            this.changeCurrIndex('-');
            this.isTransition = true;
            this.ulTranslate('100%');
        }
    }

    next(){
        this.changeCurrIndex('+');
        this.isTransition = true;
        this.ulTranslate('-100%');        
    }

    autoPlay(){
        const {playTime,notAuto} = this.props;
        if(!notAuto){
            this.timer = setTimeout(()=>{
                this.next();
            },playTime);            
        }
    }

    transitionEnd = (e) => {
        this.forceUpdate(()=>{
            this.isTransition = false;
            this.autoPlay();            
        });
    }

    render(){

        return (<div className='mm-carousel' >
            {this.createUl()}
        </div>);
    }
}

export default Carousel;

Carousel.propTypes = PropsChecker;