React Hook封装无缝轮播

App.jsx

import React from 'react';
import Carousel from './components/Carousel';

export default function App() {
    return (
        <>
            <Carousel>
                <img src='http://pic.bizhi360.com/bbpic/61/10961.jpg' alt=""/>
                <img src='http://pic.bizhi360.com/bbpic/34/11234.jpg' alt=""/>
                <img src='http://pic.bizhi360.com/bbpic/79/11079.jpg' alt=""/>
                <img src='http://pic.bizhi360.com/bbpic/30/11230.jpg' alt=""/>
            </Carousel>
        </>
    )
}

 components / Carousel / index.jsx

import React,{useState, useEffect} from "react";
import './index.css';

let lock, isRun;    // 节流锁、是否自动轮播
export default function Carousel(props) {
    let [index, setIndex] = useState(0);    // 第几张图片
    let [isTransition, setIsTransition] = useState(true);   // 是否过渡
    const imgArrNum = props.children.length;    // 图片数量
    const time = props.time ?? 500; // 过渡时间 (如果没给值,则用默认值)
    const carouselTime = time*2.4;  // 自动轮播等待时间
    let run;    // 自动轮播定时器

    // 自动轮播
    useEffect(()=>{
        if (isRun) return;
        run = setTimeout(()=>{
            throttle(next);
        }, carouselTime);
    })

    // 节流
    const throttle = (fn)=>{
        if (lock) return;
        fn();
        lock = setTimeout(() => lock=!lock, time);
    }

    // 停止轮播
    const stopRun = ()=>{
        isRun = true;
        clearTimeout(run);
    }
    // 继续轮播
    const rerun = ()=>{
        isRun = false;
        run = setTimeout(()=>{
            throttle(next);
        }, carouselTime);
    }

    // 上一张
    const prev = ()=>{
        setIndex(index-1);
        if (index === 0) {
            setIsTransition(false);
            setIndex(imgArrNum);
        }
        setTimeout(()=>{
            setIsTransition(true);
            index === 0 && setIndex(imgArrNum-1);
        });
    }
    // 下一张
    const next = ()=>{
        setIsTransition(true);
        setIndex(index+1);
        if (index === imgArrNum-1) {
            setTimeout(()=>{
                setIsTransition(false);
                setIndex(0);
            }, time);
        }
    }

    // 小圆点点击
    const dotClick = (i)=>{
        setIsTransition(true);
        setIndex(i);
    }


    return (
        <div className='carousel' onMouseEnter={stopRun} onMouseLeave={rerun}>
            <ul className='show' style={{
                left: `${-100 * index}%`,
                width: `${(imgArrNum+1) * 100}%`,
                transition: isTransition ? `${time}ms` : 'none'
            }}>

                {   // 遍历图片
                    props.children.map((img, index)=>{
                        return <li key={index}>{img}</li>
                    })
                }
                <li>{props.children[0]}</li>

            </ul>


            <p className='btn prev' onClick={()=>throttle(prev)}>&#10094;</p>
            <p className='btn next' onClick={()=>throttle(next)}>&#10095;</p>


            <ul className='dots'>
                {   // 遍历小圆点
                    props.children.map((img, i)=>{
                        if (index === imgArrNum) index = 0;
                        return <li onClick={()=>dotClick(i)} key={i} className={`dot${index === i ? ' active' : ''}`}></li>
                    })
                }
            </ul>
        </div>
    )
}

 components / Carousel / index.css

*{margin: 0; padding: 0}
li{list-style-type: none}

.carousel{
    position: relative;
    margin: 40px auto;
    width: 90vw;
    overflow: hidden;
}
.carousel:hover .btn{
    transition: .5s;
    opacity: .7;
}
.show{
    display: flex;
    position: relative;
}
.show img{
    max-width: 100%;
}
.btn{
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    padding: 12px;
    font-size: 24px;
    color: #fff;
    background-color: #282c34;
    opacity: 0;
    cursor: pointer;
    user-select: none;
    transition: .3s;
}
.btn:hover{
    opacity: 1!important;
}
.prev{
    border-radius: 0 4px 4px 0;
}
.next{
    right: 0;
    border-radius: 4px 0 0 4px;
}
.dots{
    display: flex;
    gap: 12px;
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: 4%;
}
.dot{
    width: 10px;
    height: 10px;
    background-color: #000;
    border-radius: 50%;
    opacity: .5;
    cursor: pointer;
    transition: .3s;
}
.dot:hover{
    opacity: .95;
    background-color: #fff;
}
.active{
    width: 50px;
    height: 8px;
    opacity: .95;
    background-color: #fff;
    border-radius: 16px;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值