react 实现一个无限循环的轮播器 附github地址

一个简单的轮播

为了更具有通用和参考性,轮播组件中,轮播只使用了react,没有添加其他的状态管理,或者参数类型限制的库.

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(() => {
                console.log(this.state.currentCarousel)
                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({
            currentCarousel: currentIndex
        });
    }

    /**
     * @description 轮播的mouseover事件
     */
    handleCarouselBodyMouseOver() {
        this.stopCarousel();
    }

    /**
     * @description 轮播的mouseout事件
     */
    handleCarouselBodyMouseOut() {
        this.startCarousel();
    }

    /**
     * @description 轮播的mouseout事件
     */
    handlerNext() {
        this.handlerCarousel(‘right‘);
    }

    handlerPre() {
        this.handlerCarousel(‘left‘);
    }

    getIndicatorsActive(index) {
        let active;
        // 边界判断 使在轮播在边界的时候 导航下面的小标 也能正常的添加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>

        )
    }
}

原文地址:https://www.cnblogs.com/slongs/p/10189439.html

时间: 2024-07-30 17:50:37

react 实现一个无限循环的轮播器 附github地址的相关文章

用原生的javascript 实现一个无限滚动的轮播图

说一下思路:和我上一篇博客中用JQ去写的轮播图有相同点和不同点 相同点: 首先页面布局是一样的 同样是改变.inner盒子的位置去显示不同的图片 不同点: 为了实现无限滚动需要多添加两张重复的图片 左右切换和前面的方法有所不同,前面是获取当前的索引值乘以-600px当做位移距离,现在是需要获取当前.inner的位置来加上或者减去-600来实现 下面来一步步的去实现轮播图: 首先是html <!DOCTYPE html> <html lang="en"> <

自定义完美的ViewPager 真正无限循环的轮播图

网上80%的思路关于Android轮播图无限循环都是不正确的,不是真正意义上的无限循环, 其思路大多是将ViewPager的getCount方法返回值设置为Integer.MAX_VALUE, 然后呢将ViewPager的当前展示页设置为第1000页或者是10000页,这样用户一般情况下是滑不到边界的 例如有5张图片的轮播图,item的编号为(0,1,2,3,4)当前页的页号如果是5, 这时候就将编号设置为0,即 actPosition %= datas.size();这个公式就是这么来的 这种

写一个图片轮播器(使用collectionView)

一.属性 我们需要一个 collectionView 和一个 NStimer .collectionView 用来存放需要循环播放的对象, NSTimer 用来定时滚动collectionView @interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource> @property(nonatomic,strong)UICollectionView* showCollection; @proper

IOS 05 UIScrollView介绍 图片轮播器

移动设备的屏幕?大?小是极其有限的,因此直接展?示在?用户眼前的内容也相当有限 当展?示的内容较多,超出?一个屏幕时,?用户可通过滚动?手势来查看屏幕以外的内容 普通的UIView不具备滚动功能,不能显?示过多的内容 UIScrollView是?一个能够滚动的视图控件,可以?用来展?示?大量的内容,并且可以通过滚 动查看所有的内容 在IOS中UIScrollView这个控件还是比较常用和重要的. 很多时候,我们想在UIScrollView正在滚动 或 滚动到某个位置 或者 停?止滚动 时做?一些

沉浸式图片轮播器 -- DDGBannerScrollView使用文档

写在前面 几乎每个app都会用到图片轮播器,而且图片轮播器也越来越高大上,沉浸式等拉高了APP的档次 ,没有一个高大上的图片轮播器,都不好意思上架. 像一些知名的app都采用了图片轮播的背景渐变色,举几个栗子:优酷的首页,喜马拉雅,蜻蜓fm,哔哩哔哩漫画等, page索引也是玩的很高大上,系统的早已满足不了了需求. 鉴于此和项目的需要,在前人的基础上,整理了一个这个库,志在简单的几句代码,就能让应用看上去高大上. github:[DDGBannerScrollView](https://gith

iOS开发那些事儿(一)轮播器

前言 市面上绝大部分的APP被打开之后映入眼帘的都是一个美轮美奂的轮播器,所以能做出一个符合需求.高效的轮播器成为了一个程序员的必备技能.所以今天的这篇博客就来谈谈轮播器这个看似简单的控件其中蕴含的道理. 正文  首先我们来分析一下该如何去实现一个类似下图的轮播器(图片数量.URL由服务器返回):   策略一:UIScrollView->UIImageView->NSTimer轮询 这算是常规的策略,但是如果仔细想想,如果服务器返回给你50图片是不是就需要创建50个UIImageView来做容

UIScrollView实现图片轮播器及其无限循环效果

图片轮播器: 一.实现效果 实现图片的自动轮播            二.实现代码 storyboard中布局 代码: 1 #import "YYViewController.h" 2 3 @interface YYViewController () <UIScrollViewDelegate> 4 @property (weak, nonatomic) IBOutlet UIScrollView *scrollview; 5 /** 6 * 页码 7 */ 8 @prop

一步一步拆解一个简单的iOS轮播图(三图)

导言(可以不看): 不吹不黑,也许是东半球最简单的iOS轮播图拆分注释(讲解不敢当)了(tree new bee).(一句话包含两个人,你能猜到有谁吗?提示:一个在卖手机,一个最近在卖书)哈哈... 我第一次项目中需要使用轮播图的时候我是用的别人写好的一个轮子,那个轮播封装很多东西,包括比如可以设置pageControl的位置,可以传图片url或本地图片,缓存网络图片等等.但是我觉得没必要搞那么复杂,我喜欢简单并足够做事的东西.现在有时间便想自己把它拆解一下.看了一些简书上一些作者写的关于轮播图

记一个好用的轮播图的FlexSlider

之前给自己公司的主页套用过一个js动态生成的轮播图,但是从载入的时机和载入后的效果都不太理想,又懒得去优化了,这次偶然遇到一个比较不错的轮播图的js插件,记录之. 首先它是给予jquery的,引进jquery和jquery.flexslider-min.js,然后定义div范围,在div内定义好要轮播的ul和li标签,然后设置flex参数渲染即可.不多说,上代码 <html> <body> <div class="flexslider"> <u