import { useEffect, useRef, useState } from "react"; import type { RefObject } from "react"; import { useRouter } from "next/navigation"; import type { ImageData, LoopMode, Neighbors } from "../types.ts"; interface UseImageCarouselProps { images: ImageData["images"]; isPlaying: boolean; loopMode: LoopMode; neighbors: Neighbors; volume: number; audioRef: RefObject; scrollerRef: RefObject; setProgress: (progress: number) => void; /** 单张图片显示时长(毫秒),默认 5000ms */ segmentMs?: number; } export function useImageCarousel({ images, isPlaying, loopMode, neighbors, volume, audioRef, scrollerRef, setProgress, segmentMs = 5000, }: UseImageCarouselProps) { const router = useRouter(); const [idx, setIdx] = useState(0); const [segProgress, setSegProgress] = useState(0); const segStartRef = useRef(null); const idxRef = useRef(0); const rafRef = useRef(null); useEffect(() => { idxRef.current = idx; }, [idx]); // BGM 控制 useEffect(() => { const el = audioRef.current; if (!el) return; el.volume = volume; if (isPlaying) { el.play().catch(() => {}); } else { el.pause(); } }, [audioRef, isPlaying, volume]); // 自动切页 useEffect(() => { if (!images?.length) return; if (segStartRef.current == null) segStartRef.current = performance.now(); let lastTs = performance.now(); const tick = (ts: number) => { if (!images?.length) return; if (!isPlaying) segStartRef.current! += ts - lastTs; lastTs = ts; let start = segStartRef.current!; let localIdx = idxRef.current; let elapsed = ts - start; // 获取当前图片的显示时长(动图使用其 duration,静态图片使用 segmentMs) const getCurrentSegmentDuration = (index: number) => { const img = images[index]; return img?.duration ?? segmentMs; }; let currentSegmentDuration = getCurrentSegmentDuration(localIdx); while (elapsed >= currentSegmentDuration) { elapsed -= currentSegmentDuration; if (localIdx >= images.length - 1) { if (loopMode === "sequential" && neighbors?.next) { router.push(`/aweme/${neighbors.next.aweme_id}`); return; } localIdx = 0; } else { localIdx = localIdx + 1; } // 更新下一张图片的时长 currentSegmentDuration = getCurrentSegmentDuration(localIdx); } segStartRef.current = ts - elapsed; if (localIdx !== idxRef.current) { idxRef.current = localIdx; setIdx(localIdx); // 虚拟滚动不需要实际滚动 DOM } const localSeg = Math.max(0, Math.min(1, elapsed / currentSegmentDuration)); setSegProgress(localSeg); // 计算总进度:已完成的图片 + 当前图片的进度 let totalProgress = 0; for (let i = 0; i < localIdx; i++) { totalProgress += 1; } totalProgress += localSeg; setProgress(totalProgress / images.length); rafRef.current = requestAnimationFrame(tick); }; rafRef.current = requestAnimationFrame(tick); return () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); rafRef.current = null; }; }, [images, isPlaying, loopMode, neighbors?.next, router, scrollerRef, setProgress, segmentMs]); return { idx, setIdx, segProgress, segStartRef, idxRef, }; }