//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