React实现图片轮播

React实现图片轮播

//SwiperImg.tsx
import React, { useReducer, useRef, useState } from 'react'
import styles from './SwiperImg.module.css'

let timerState1: NodeJS.Timer
let timerState2: NodeJS.Timer

//
enum Direction {
    forwrad = "forwrad",
    back = 'back'
}

function reducer(state: { index: number }, index: number) {
    state.index = index;
    return state;
}

function reducer2(state: { colorIndex: number }, newIndex: number) {
    state.colorIndex = newIndex;
    return state
}

//轮播图片urls
interface IProps {
    slideUrls: string[]
}

function SwiperImg(props: IProps) {
    const [state, dispatch] = useReducer(reducer, { index: 0 });
    const [state2, dispatch2] = useReducer(reducer2, { colorIndex: 0 });
    let [left, setLeft] = useState(0)
    let myRef = useRef<HTMLUListElement>(null);
    // 默认100%宽
    let boxWidth = 100

    function changeColorIndex(next: number) {
        if (next === props.slideUrls.length) {
            dispatch2(0)
        } else (
            dispatch2(next)
        )
    }

    // 向前移动一张图片
    function forwrad() {
        let tag = (state.index + 1) % (props.slideUrls.length + 1)
        dispatch(tag)
        changeColorIndex(tag)
        animate(tag, Direction.forwrad)
    }

    // 向后移动一张图片
    function back() {
        let tag: number = state.index
        if (state.index === 0) {
            tag = props.slideUrls.length;
        } else {
            tag = state.index - 1
        }
        dispatch(tag);
        changeColorIndex(tag)
        animate(tag, Direction.back)
    }


    // 移动动画
    function animate(next_index: number, direction: Direction) {
        let target: number = -boxWidth * next_index;
        if (direction == Direction.forwrad) {
            //向前,且下一张图为第一张,直接跳到第一张图,再继续向前
            if (next_index === 0) {
                //直接跳到第一章图
                setLeft(() => 0);
                dispatch(1)
                changeColorIndex(1)
                target = -boxWidth;
            }
        } else if (direction === Direction.back) {
            // 向后,且下一张图为最后张,直接跳到最后一张,再继续向后
            if (next_index === props.slideUrls.length) {
                setLeft(() => -boxWidth * props.slideUrls.length);
                dispatch(props.slideUrls.length - 1)
                changeColorIndex(props.slideUrls.length - 1)
                target = -boxWidth * (props.slideUrls.length - 1);
            }
        }

        clearInterval(timerState1)
        timerState1 = setInterval(() => {
            let berforeLeft = myRef.current?.style.left!;
            let berforeLeftNum = Number(berforeLeft.slice(0, berforeLeft.length - 1))
            let step = (target - berforeLeftNum) / 10;
            step = step > 0 ? Math.ceil(step) : Math.floor(step);
            if (myRef.current?.offsetLeft === target) {
                clearInterval(timerState1)
            } else {
                setLeft(() => berforeLeftNum + step)
            }
        }, 15)
    }


    //点击跳转特定的图片
    function JumpToTheSpecifiedPicture(nextIndex: number) {
        dispatch(nextIndex)
        changeColorIndex(nextIndex)
        // setIndex(nextIndex)
        setLeft(-boxWidth * nextIndex)
    }

    // 鼠标移出,添加定时器,让图片轮播
    function handleMouseOut() {
        clearInterval(timerState2)
        timerState2 = setInterval(() => { forwrad(); }, 2000)
    }

    //鼠标移入,删除定时器,让图片停止轮播
    function handleMouseOver() {
        clearInterval(timerState2)
    }

    return (
        <div
            className={styles.swiperImg}
            style={{ 'width': "100%" }}
            onMouseOver={handleMouseOver}
            onMouseOut={handleMouseOut}
        >
            <ul
                ref={myRef}
                style={{
                    'width': `${100 * (props.slideUrls.length + 1)}%`,
                    'left': `${left}%`
                }}
            >
                {
                    props.slideUrls.map((item, index) => {
                        return (
                            <li key={index} style={{ 'width': `${100 / (props.slideUrls.length + 1)}%` }}>
                                <img
                                    style={{ 'width': '100%' }}
                                    src={item}
                                    alt=""
                                />
                            </li>
                        )
                    })
                }

                <li style={{ 'width': `${100 / (props.slideUrls.length + 1)}%` }}>
                    <img
                        style={{ 'width': '100%' }}
                        src={props.slideUrls[0]}
                        alt=""
                    />
                </li>
            </ul>


            <div className={styles.btuList}>
                <button onClick={back} className={styles.clickBut}><div className={styles.arrowLeft}></div></button>
                <button onClick={forwrad} className={styles.clickBut}><div className={styles.arrowRight}></div></button>
            </div>

            <div className={styles.dotList}>
                {
                    props.slideUrls.map((item, index) => {
                        return (
                            <div
                                key={index}
                                className={styles.dot}
                                style={state2.colorIndex === index ? { 'background': '#8B8B7A' } : { 'background': ' aliceblue' }}
                                onClick={e => { JumpToTheSpecifiedPicture(index) }}
                            >
                            </div>
                        )
                    })
                }
            </div>
        </div>
    )
}
export default SwiperImg;

/*SwiperImg.module.css*/
.swiperImg {
    overflow: hidden;
    position: relative;

}

.swiperImg ul {
    margin: 0px;
    padding: 0px;
    position: relative;
}

.swiperImg ul li {
    list-style-type: none;
    float: left;
}

.clickBut {
    background-color: transparent;
    border: 0px;
    outline: none;
}

.btuList {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;

    width: 100%;
    position: absolute;
    bottom: 50%
}

.dotList {
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;

    width: 100%;
    position: absolute;
    bottom: 10px;

}

.dot {
    ---size: 10px;
    width: var(---size);
    height: var(---size);
    margin-left: 10px;
    margin-right: 10px;
    border-radius: 50%;
    border: 1px solid #DCDCDC;
}

.arrowLeft {
    width: 0;
    height: 0;
    border: 15px solid;
    border-color: transparent #B0C4DE transparent transparent;
    position: relative;
}

.arrowLeft::after {
    content: '';
    position: absolute;
    top: -10px;
    left: -5px;
    border: 10px solid;
    border-color: transparent white transparent transparent;
}

.arrowRight {
    width: 0;
    height: 0;
    border: 15px solid;
    border-color: transparent transparent transparent #B0C4DE;
    position: relative;
}

.arrowRight::after {
    content: '';
    position: absolute;
    top: -10px;
    right: -5px;
    border: 10px solid;
    border-color: transparent transparent transparent white;
}

调用图片轮播组件

import React from 'react'
import SwiperImg from './components/SwiperImg'
import styles from './App.module.css'
import img1 from './images/1.webp'
import img2 from './images/2.webp'
import img3 from './images/3.webp'
import img4 from './images/4.webp'
function App() {

  return (
    <div className={styles.app}>
      <SwiperImg slideUrls={[img1, img2, img3, img4]} />
    </div>
  )
}

export default App
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值