正文

需求是做一个无缝轮播图,我说这不是有很多现成的轮子吗?后来了解到他有一个特殊的需求,他要求小圆点需要在轮播图外面,因为现在大部分插件都是将小圆点写在轮播图内部的,这对于不了解插件内部结构的小伙伴确实不知道如何修改。

很久没有写插件的我准备写一个插件(react)

无缝轮播

无缝轮播从最后一张到第一张的过程中不会原路返回,它就像轮子似的,从结束到开始是无缝连接的,非常自然地循环下去。

实现思路

轮播图的实现思路有很多,我们这里采用的是最简单的轮播图方案,如上图,即当轮播图轮播到第x张图片时,当前整个轮播图列表中只保留第x张图片,其余图片dom全部隐藏掉即可。

那么大家有一个疑问,这样不会导致切换时不连贯吗?这个大家不必担心,我们可以在上一个轮播图小时和下一个轮播图展现时增加动画效果,来达到连贯的感觉。

构思使用时代码结构

参考了大部分轮播图组件,得出来下面的这种使用结构。

import Carousel,{ Item } from '组件'
render(){
    return (
        <Carousel>
            <Item><img src="xxx" /></Item>
            <Item><img src="xxx" /></Item>
            <Item><img src="xxx" /></Item>
        </Carousel>
    )
}

Carousel组件

新建Carousel组件,这个组件是组件的整体框架文件。

内部增加inner div 来充当当前展示轮播图的视口

const Carousel=()=>{
    return (
        <div className={'carousel'}>
            <div className={'carousel-inner'}> 
                {xxx轮播图xxx}
            </div> 
        </div>
    )
} 

overflow:hidden是关键

.inner{
    width:100%;
    height:100%;
    position: relative;
    overflow: hidden;
} 

CarouselItem组件

新建CarouselItem组件,这个组件是Carousel组件的子组件,是轮播图列表每一项的容器。

const CarouselItem=(props)=>{ 
    return (
        <div className={'carousel-item'}>
            {props.children}
        </div>
    )
}

注意 这里需要使用top0 left0 不然显示的时候会从上往上偏移 导致错误显示

.carousel-item{
    position: absolute;
    left:0;
    top:0;
    width: 100%;
    height:100%; 
}

完善组件

  • 如何显示当前轮播图元素

之前我们说过这次我们轮播图的核心思路是显示当前元素,那么什么情况下显示当前元素呢?

carousel组件内有一个state表示当前轮播到第几张图 我们这里叫current,而根据传入carousel的元素排序,我们可以在item内部拿到当前是第几张图片,然后2者如果是相等的,就显示当图片。

我们如何获取元素当前的index呢?我们可以利用react提供的解析children的api

// util
import React from "react";
export function injecteIndex(children:React.ElementType,current):any{
    let result:React.ReactElement[]=[];
    React.Children.forEach(children,(item,index)=>{
        result.push(React.cloneElement((item as any),{
            //selfIndex即为轮播图的index
            selfIndex:index,
            key:index,
            current
        }))
    });
    return result;
}
//carousel组件
//initial 为传入配置 默认为0 即默认展示第一张图
const Carousel=()=>{
    const {
        initial
    }=props;
    const [current,setCurrent]=useState<number>(initial);
    return (
        <div className={'carousel'}>
            <div className={'carousel-inner'}> 
                {injecteIndex(children,current)}
            </div> 
        </div>
    )
}  
//carousel-item组件
const CarouselItem=(props)=>{ 
    const { selfIndex,current }=props;
    const visible=selfIndex===current
    return (
        {visible && <div className={'carousel-item'}>
            {props.children}
        </div>}
    )
}
  • 实现autoPlay

上面我们其实已经实现了第一张图的展示,那么我们如何让他动起来呢?其实也很简单,我们一起来实现一下

//useLatest
import { useEffect, useRef } from "react"
export default (params:any)=>{
    const latest=useRef();
    useEffect(()=>{
        latest.current=params;
    })
    return latest;
}
//carousel组件 
const Carousel=(props)=>{
    const {
        //initial 为传入配置 默认为0 即默认展示第一张图
        initial=0,
        //是否自动轮播 默认为是
        autoplay=true,
        //时间间隔 默认为3秒
        interval=3000
    }=props;
    //新建定时器存储变量
    const timer:any=useRef(null);
    const [current,setCurrent]=useState<number>(initial);
    const [itemLength]=useState<number>(React.Children.count(children)); 
    //解决闭包问题
    const latest:any=useLatest(current); 
    const autoPlay=()=>{
        //设置定时器 每隔3s切换到下一张图片
        timer.current=setInterval(()=>{
            setStep('next');
        },interval);
    }
    const setStep=(direction:'prev'|'next')=>{
        switch(direction){
            case 'prev':
                let prevStep:number=latest.current-1;
                //当为第一张时 跳到第5张
                if(prevStep===-1){
                    prevStep=itemLength-1;
                }
                setCurrent(prevStep);
                break;
            case 'next':
                let nextStep:number=latest.current 1;
                //当为最后一张时 跳到第1张
                if(nextStep===itemLength){
                    nextStep=0;
                }
                setCurrent(nextStep);
                break;
            default:
        }
    }
    useEffect(()=>{
        if(autoplay){
            //自动轮播
            autoPlay();
        }
        return ()=>{
            //销毁定时器
            clearInterval(timer.current);
            timer.current=null;
        }
    },[autoplay]);
    return (
        <div className={'carousel'}>
            <div className={'carousel-inner'}> 
                {injecteIndex(children,current)}
            </div> 
        </div>
    )
}  
```# 完成动画
其实上面我们已经把无缝轮播业务逻辑完成了,那么如何让他轮播起来呢?我们这里使用react官方推荐的一个过渡库,因为react并没有像vue为我们提供transition api。
```js
const CarouselItem=(props)=>{ 
    const {  
        children,
        selfIndex 
    }=props; 
    const visible=selfIndex===current; 
    return  (
        <CSSTransition mountOnEnter unmountOnExit appear in={visible} timeout={500}  classNames={'carousel'}>
            <div className={'carousel-item'} >
                {children}
            </div>
        </CSSTransition>
    ) 
});
.carousel-enter-active,.carousel-exit-active{
        transition: all 500ms linear;
}
.carousel-enter{ 
        transform: translateX(100%);
        opacity: 0.8;
}
.carousel-enter-active{
        transform: translateX(0);
        opacity: 1;
}
.carousel-exit{
        transform: translateX(0); 
        opacity: 1;
}
.carousel-exit-active{
        transform: translateX(-100%); 
        opacity: 0.8;
}

之前我们设置的top:0 left:0 可以得出轮播元素的原点都是容器的左上角 在enter过程将translateX从100到0 即可展示从右往左的动画效果 在exit过程前将translateX从0到-100 即可展示从左往右的动画效果

完成小圆点

其实让我写轮播图的老兄 最大的难点是小圆点的位置 因为大部分轮播图 小圆点部分都是写在inner里面的 而inner元素为overflow:hidden,即不管如何小圆点,他都会溢出隐藏。所以这次我们把小圆点放在inner元素上,并且提供一个属性让小圆点可调。

//carousel 
<div className={classes}>
    <div className={'inner'}>
        {injecteIndex(children)}
    </div>
    <Dots length={itemLength}  position={dotPosition}/>
</div>
//dots原点
<div className={classnames(
            classes, 
    )} style={{...position}}>
            {
                newArray.map((item,index)=>(
                    <div className={classnames(`${prefixCls}-item`,{
                        'active':current===index
                    })} key={index} onClick={()=>onClick(index)}/>
                ))
            }
</div>

实现效果

源码地址

如果大家有想使用的话 可以放心 使用 源码已发到github和npm上面

npm install @parrotjs/carousel -S

以上就是react 组件实现无缝轮播示例详解的详细内容,更多关于react 组件无缝轮播的资料请关注Devmax其它相关文章!

react 组件实现无缝轮播示例详解的更多相关文章

  1. bootstrapv4轮播图去除两侧阴影及线框的方法

    这篇文章主要介绍了bootstrapv4轮播图去除两侧阴影及线框的方法,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. AmazeUI图片轮播效果的示例代码

    这篇文章主要介绍了AmazeUI图片轮播效果的示例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. ios – React native链接到另一个应用程序

    如果是错误的,有人知道如何调用正确的吗?

  4. ios – React Native – 在异步操作后导航

    我正在使用ReactNative和Redux开发移动应用程序,我正面临着软件设计问题.我想调用RESTAPI进行登录,如果该操作成功,则导航到主视图.我正在使用redux和thunk所以我已经实现了异步操作,所以我的主要疑问是:我应该把逻辑导航到主视图?我可以直接从动作访问导航器对象并在那里执行导航吗?.我对组件中的逻辑没有信心.似乎不是一个好习惯.有没有其他方法可以做到这一点?

  5. 在ios中使用带有React Native(0.43.4)的cocoapods的正确方法是什么?

    我已经挖掘了很多帖子试图使用cocoapods为本地ios库设置一个反应原生项目,但我不可避免地在#import中找到了丢失文件的错误.我的AppDelegate.m文件中的语句.什么是使用反应原生的可可豆荚的正确方法?在这篇文章发表时,我目前的RN版本是0.43.4,而我正在使用Xcode8.2.1.这是我的过程,好奇我可能会出错:1)

  6. ios – React Native WebView滚动行为无法按预期工作

    如何确保滚动事件的行为与ReactNative应用程序中的浏览器相同?

  7. ios – React Native – BVLinearGradient – 找不到’React/RCTViewManager.h’文件

    谢谢.解决方法几天前我遇到了完全相同的问题.问题是在构建应用程序时React尚未链接.试试这个:转到Product=>Scheme=>管理方案…=>点击你的应用程序Scheme,然后点击Edit=>转到Build选项卡=>取消选中ParallelizeBuild然后点击标志添加目标=>搜索React,选择第一个名为React的目标,然后单击Add然后在目标列表中选择React并将其向上拖动到该列表中的第一个.然后转到Product=>再次清理并构建项目.这应该有所帮助.

  8. ios – React Native – NSNumber无法转换为NSString

    解决方法在你的fontWeight()函数中也许变成:

  9. ios – React native error – react-native-xcode.sh:line 45:react-native:command not found命令/ bin/sh失败,退出代码127

    尝试构建任何(新的或旧的)项目时出现此错误.我的节点是版本4.2.1,react-native是版本0.1.7.我看过其他有相同问题的人,所以我已经更新了本机的最新版本,但是我仍然无法通过xcode构建任何项目.解决方法要解决此问题,请使用以下步骤:>使用节点版本v4.2.1>cd进入[你的应用]/node_modules/react-native/packager>$sh./packager.s

  10. 反应原生 – 如何通过Xcode构建React Native iOS应用程序到设备?

    我试图将AwesomeProject应用程序构建到设备上.构建成功并启动屏幕显示,但后来我看到一个红色的“无法连接到开发服务器”屏幕.它表示“确保节点服务器正在运行–从Reactroot运行”npmstart“.看起来节点服务器已经运行,因为当我做npm启动时,我收到一个EADDRINUSE消息,表示该端口已经在使用.解决方法从设备访问开发服务器您可以使用开发服务器快速迭代设备.要做到这一点,你的

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部