import { forwardRef, useEffect, useRef, useState } from "react"; import type { ImageData } from "../types.ts"; interface ImageCarouselProps { images: ImageData["images"]; currentIndex: number; onTogglePlay: () => void; } export const ImageCarousel = forwardRef( ({ images, currentIndex, onTogglePlay }, ref) => { const [offset, setOffset] = useState(0); const [isTransitioning, setIsTransitioning] = useState(false); const containerRef = useRef(null); const videoRefs = useRef>(new Map()); const playedVideos = useRef>(new Set()); // 虚拟滚动:只渲染当前图片和前后各一张 const visibleIndices = (() => { const indices: number[] = []; if (currentIndex > 0) indices.push(currentIndex - 1); indices.push(currentIndex); if (currentIndex < images.length - 1) indices.push(currentIndex + 1); return indices; })(); // 当 currentIndex 变化时,触发滚动动画 useEffect(() => { setIsTransitioning(true); setOffset(-currentIndex * 100); const timer = setTimeout(() => { setIsTransitioning(false); }, 300); // 与 CSS transition 时间匹配 return () => clearTimeout(timer); }, [currentIndex]); // 管理动图播放:进入视口时播放一次 useEffect(() => { const currentImage = images[currentIndex]; if (!currentImage?.animated) return; const videoKey = currentImage.id; const videoEl = videoRefs.current.get(videoKey); if (videoEl) { // 检查是否已经播放过 if (!playedVideos.current.has(videoKey)) { // 重置并播放 videoEl.currentTime = 0; videoEl.play().catch(() => {}); playedVideos.current.add(videoKey); } else { // 已播放过,重置到开头但不自动播放 videoEl.currentTime = 0; videoEl.play().catch(() => {}); } } }, [currentIndex, images]); // 当切换到其他图片时,清除已播放标记(切回来会重新播放) useEffect(() => { const currentImage = images[currentIndex]; if (currentImage?.animated) { const videoKey = currentImage.id; // 清除其他视频的播放记录 playedVideos.current.forEach(key => { if (key !== videoKey) { playedVideos.current.delete(key); } }); } }, [currentIndex, images]); const handleVideoRef = (el: HTMLVideoElement | null, imageId: string) => { if (el) { videoRefs.current.set(imageId, el); } else { videoRefs.current.delete(imageId); } }; return (
{visibleIndices.map((i) => { const img = images[i]; return (
{img.animated ? (
); })}
); } ); ImageCarousel.displayName = "ImageCarousel";