import { useEffect, useRef, useState } from "react"; import type { RefObject } from "react"; import { useRouter } from "next/navigation"; import type { ImageData, LoopMode, Neighbors } from "../types"; 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; while (elapsed >= segmentMs) { elapsed -= segmentMs; if (localIdx >= images.length - 1) { if (loopMode === "sequential" && neighbors?.next) { router.push(`/aweme/${neighbors.next.aweme_id}`); return; } localIdx = 0; } else { localIdx = localIdx + 1; } } segStartRef.current = ts - elapsed; if (localIdx !== idxRef.current) { idxRef.current = localIdx; setIdx(localIdx); const el = scrollerRef.current; if (el) el.scrollTo({ left: localIdx * el.clientWidth, behavior: "smooth" }); } const localSeg = Math.max(0, Math.min(1, elapsed / segmentMs)); setSegProgress(localSeg); setProgress((localIdx + localSeg) / images.length); rafRef.current = requestAnimationFrame(tick); }; rafRef.current = requestAnimationFrame(tick); return () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); rafRef.current = null; }; }, [images?.length, isPlaying, loopMode, neighbors?.next, router, scrollerRef, setProgress, segmentMs]); return { idx, setIdx, segProgress, segStartRef, idxRef, }; }