76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
|
import React, { useRef, useState, useEffect } from 'react';
|
||
|
import Autoplay from "embla-carousel-autoplay";
|
||
|
import {
|
||
|
Carousel,
|
||
|
CarouselContent,
|
||
|
CarouselItem,
|
||
|
type CarouselApi
|
||
|
} from "@repo/ui/components/carousel";
|
||
|
|
||
|
interface CarouselComponentProps {
|
||
|
carouselData: { id: number; image: string; title: string }[];
|
||
|
}
|
||
|
|
||
|
const CarouselComponent: React.FC<CarouselComponentProps> = ({ carouselData }) => {
|
||
|
const [carouselAPI, setCarouselAPI] = useState<CarouselApi | null>(null);
|
||
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||
|
const plugin = useRef(Autoplay({ delay: 2000, stopOnInteraction: true }));
|
||
|
|
||
|
// 监听轮播图变化
|
||
|
useEffect(() => {
|
||
|
if (!carouselAPI) return;
|
||
|
|
||
|
const updateCurrentIndex = () => {
|
||
|
setCurrentIndex(carouselAPI.selectedScrollSnap());
|
||
|
};
|
||
|
|
||
|
carouselAPI.on("select", updateCurrentIndex);
|
||
|
|
||
|
return () => {
|
||
|
carouselAPI.off("select", updateCurrentIndex);
|
||
|
};
|
||
|
}, [carouselAPI]);
|
||
|
|
||
|
// 滚动到指定索引
|
||
|
const scrollToIndex = (index: number) => {
|
||
|
if (carouselAPI) {
|
||
|
carouselAPI.scrollTo(index);
|
||
|
setCurrentIndex(index);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return (
|
||
|
<div className="relative"> {/* 添加相对定位 */}
|
||
|
<Carousel
|
||
|
className="h-[255px] w-[400px]"
|
||
|
setApi={setCarouselAPI}
|
||
|
plugins={[plugin.current, Autoplay({ delay: 2000, stopOnInteraction: true })]}
|
||
|
onMouseEnter={plugin.current.stop}
|
||
|
onMouseLeave={plugin.current.reset}
|
||
|
>
|
||
|
<CarouselContent>
|
||
|
{carouselData.map((item) => (
|
||
|
<CarouselItem key={item.id}>
|
||
|
<div className="h-[255px] w-[400px] relative">
|
||
|
<img src={item.image} alt={item.title} className="w-full h-full object-cover rounded-lg" />
|
||
|
</div>
|
||
|
</CarouselItem>
|
||
|
))}
|
||
|
</CarouselContent>
|
||
|
</Carousel>
|
||
|
|
||
|
{/* 圆点指示器 */}
|
||
|
<div className="absolute bottom-2 right-2 flex justify-center mb-[20px]"> {/* 添加绝对定位 */}
|
||
|
{carouselData.map((_, index) => (
|
||
|
<button
|
||
|
key={index}
|
||
|
className={`w-3 h-3 rounded-full mx-1 ${currentIndex === index ? 'bg-red-500' : 'bg-white'}`}
|
||
|
onClick={() => scrollToIndex(index)}
|
||
|
/>
|
||
|
))}
|
||
|
</div>
|
||
|
</div>
|
||
|
);
|
||
|
};
|
||
|
|
||
|
export default CarouselComponent;
|