前后切换轮播图
实现前后切换的轮播图依靠transform这个属性,只要得到每张图片的宽度,左右移动时候根据其第几张图片的位置切换即可。
无缝衔接轮播图
需要添加两张图片,把第一张图片复制一份添加到末尾,然后把末尾的图片复制一份添加到开头。
当是最后第二张图片时候再往右,这个时候就不加动画的切换到第一张图片,然后添加动画切换到第二张图片,这样就实现了往右滑动的无缝轮播。
!!!切换到第二张图片时候需要强制渲染,不然会添加动画的代码会覆盖不添加动画的代码
往左同理
实现代码
import { useEffect, useState, useRef, useLayoutEffect } from 'react';
// 实现轮播图
import One from '../../assets/images/1.jpeg';
import Last from '../../assets/images/1.jpeg';
import Two from '../../assets/images/2.jpeg';
import Three from '../../assets/images/3.jpeg';
import Start from '../../assets/images/3.jpeg';
import './style.css';
export default function Swiper() {
const data = [One, Two, Three];
const [imagesInfo, setImagesInfo] = useState([]);
const [currentIndex, setCurrentIndex] = useState(0);
const [autoPlayFlag, setAutoPlayFlag] = useState(true);
const containerRef = useRef(null);
const flagRef = useRef(false);
const len = data.length;
useEffect(() => {
let startX = 0;
const images = data.map((item) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = item;
img.onload = () => {
startX += img.width;
resolve({ src: item, widthSum: startX, height: img.height, width: img.width });
}
});
});
Promise.all(images).then((res) => {
setImagesInfo(res);
});
}, [])
useEffect(() => {
let timer = null;
if (containerRef.current) {
const images = containerRef.current.children;
if (flagRef.current) {
for (let item of images) {
item.style.transition = 'none';
if (currentIndex === 0) {
item.style.transform = `translate(${0}px)`;
} else {
item.style.transform = `translate(${-(imagesInfo[currentIndex].widthSum + imagesInfo[len - 1].width)}px)`;
}
}
// 强制渲染
containerRef.current.getBoundingClientRect();
// }
for (let item of images) {
item.style.transition = 'transform .5s ease-out';
item.style.transform = `translate(${imagesInfo[currentIndex].width - imagesInfo[currentIndex].widthSum - images[0].width}px)`;
}
if (autoPlayFlag) {
timer = autoPlay();
}
}
return () => {
timer && timer();
}
})
const forward = (e) => {
if (currentIndex === len - 1) {
// 消除动画效果
flagRef.current = true;
console.log('%c [ 消除动画效果 ]-34', 'font-size:13px; background:pink; color:#bf2c9f;', "无缝当前是最后一张")
// 回到第一张
setCurrentIndex(0);
} else {
flagRef.current = false;
setCurrentIndex(currentIndex + 1);
console.log("下一张", currentIndex);
}
}
const backward = (e) => {
if (currentIndex === 0) {
// 无缝轮播
flagRef.current = true;
console.log('%c [ ]-45', 'font-size:13px; background:pink; color:#bf2c9f;', "无缝轮播 当前是第一张");
setCurrentIndex(len - 1);
} else {
flagRef.current = false;
setCurrentIndex(currentIndex - 1);
console.log("上一张", currentIndex);
}
}
const autoPlay = () => {
const timer = setInterval(() => {
forward();
}, 3000);
return () => {
clearInterval(timer);
}
}
return (
<div>
{imagesInfo.length && (
<div ref={containerRef} className="container">
<img key={'start'} src={Start} alt="img" />
{imagesInfo.map((item, index) => {
return <img key={index} src={item.src} alt="img" />
})}
<img key={'Last'} src={Last} alt="img" />
</div>
)}
<div>
<button onClick={() => {
setAutoPlayFlag(false);
backward();
}}>上一张</button>
<button onClick={ () => {
setAutoPlayFlag(false);
forward();
}}>下一张</button>
</div>
</div>
)
}