重构client,拆分组件
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import type { RefObject } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import type { ImageData, LoopMode, Neighbors } from "../types";
|
||||
|
||||
const SEGMENT_MS = 5000;
|
||||
|
||||
interface UseImageCarouselProps {
|
||||
images: ImageData["images"];
|
||||
isPlaying: boolean;
|
||||
loopMode: LoopMode;
|
||||
neighbors: Neighbors;
|
||||
volume: number;
|
||||
audioRef: RefObject<HTMLAudioElement | null>;
|
||||
scrollerRef: RefObject<HTMLDivElement | null>;
|
||||
setProgress: (progress: number) => void;
|
||||
}
|
||||
|
||||
export function useImageCarousel({
|
||||
images,
|
||||
isPlaying,
|
||||
loopMode,
|
||||
neighbors,
|
||||
volume,
|
||||
audioRef,
|
||||
scrollerRef,
|
||||
setProgress,
|
||||
}: UseImageCarouselProps) {
|
||||
const router = useRouter();
|
||||
const [idx, setIdx] = useState(0);
|
||||
const [segProgress, setSegProgress] = useState(0);
|
||||
|
||||
const segStartRef = useRef<number | null>(null);
|
||||
const idxRef = useRef<number>(0);
|
||||
const rafRef = useRef<number | null>(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 >= SEGMENT_MS) {
|
||||
elapsed -= SEGMENT_MS;
|
||||
|
||||
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 / SEGMENT_MS));
|
||||
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]);
|
||||
|
||||
return {
|
||||
idx,
|
||||
setIdx,
|
||||
segProgress,
|
||||
segStartRef,
|
||||
idxRef,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user