import { useEffect, useRef } from "react"; import type { RefObject } from "react"; import { useRouter } from "next/navigation"; import type { Neighbors } from "../types"; interface UseNavigationProps { neighbors: Neighbors; isVideo: boolean; mediaContainerRef: RefObject; videoRef?: RefObject; prevImg?: () => void; nextImg?: () => void; togglePlay: () => void; } export function useNavigation({ neighbors, isVideo, mediaContainerRef, videoRef, prevImg, nextImg, togglePlay, }: UseNavigationProps) { const router = useRouter(); const wheelCooldownRef = useRef(0); // 预取路由 useEffect(() => { if (!neighbors) return; if (neighbors.next) router.prefetch(`/aweme/${neighbors.next.aweme_id}`); if (neighbors.prev) router.prefetch(`/aweme/${neighbors.prev.aweme_id}`); }, [neighbors, router]); // 鼠标滚轮切换 useEffect(() => { const el = mediaContainerRef.current; if (!el) return; const onWheel = (e: WheelEvent) => { if (e.ctrlKey) return; const now = performance.now(); if (now - wheelCooldownRef.current < 700) return; const dy = e.deltaY; if (Math.abs(dy) < 40) return; if ((dy > 0 && neighbors?.next) || (dy < 0 && neighbors?.prev)) { e.preventDefault(); } if (dy > 0 && neighbors?.next) { wheelCooldownRef.current = now; router.push(`/aweme/${neighbors.next.aweme_id}`); } else if (dy < 0 && neighbors?.prev) { wheelCooldownRef.current = now; router.push(`/aweme/${neighbors.prev.aweme_id}`); } }; el.addEventListener("wheel", onWheel, { passive: false }); return () => el.removeEventListener("wheel", onWheel as any); }, [neighbors, mediaContainerRef, router]); // 键盘快捷键 useEffect(() => { const onKeyDown = (e: KeyboardEvent) => { const target = e.target as HTMLElement; if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) { return; } const key = e.key.toLowerCase(); if (key === "arrowup" || key === "w") { e.preventDefault(); const now = performance.now(); if (now - wheelCooldownRef.current < 700) return; if (neighbors?.prev) { wheelCooldownRef.current = now; router.push(`/aweme/${neighbors.prev.aweme_id}`); } } else if (key === "arrowdown" || key === "s") { e.preventDefault(); const now = performance.now(); if (now - wheelCooldownRef.current < 700) return; if (neighbors?.next) { wheelCooldownRef.current = now; router.push(`/aweme/${neighbors.next.aweme_id}`); } } else if (key === "arrowleft" || key === "a") { e.preventDefault(); if (isVideo) { const v = videoRef?.current; if (v && v.duration) { v.currentTime = Math.max(0, v.currentTime - 5); } } else { prevImg?.(); } } else if (key === "arrowright" || key === "d") { e.preventDefault(); if (isVideo) { const v = videoRef?.current; if (v && v.duration) { v.currentTime = Math.min(v.duration, v.currentTime + 5); } } else { nextImg?.(); } } else if (key === " ") { e.preventDefault(); togglePlay(); } }; window.addEventListener("keydown", onKeyDown); return () => window.removeEventListener("keydown", onKeyDown); }, [isVideo, neighbors, router, videoRef, prevImg, nextImg, togglePlay]); // 浏览器返回事件 useEffect(() => { window.history.pushState({ interceptBack: true }, ""); const handlePopState = () => { window.close(); setTimeout(() => { if (!document.hidden) { router.push("/"); } }, 100); }; window.addEventListener("popstate", handlePopState); return () => { window.removeEventListener("popstate", handlePopState); }; }, [router]); }