重构client,拆分组件
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
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<HTMLDivElement | null>;
|
||||
videoRef?: RefObject<HTMLVideoElement | null>;
|
||||
prevImg?: () => void;
|
||||
nextImg?: () => void;
|
||||
togglePlay: () => void;
|
||||
}
|
||||
|
||||
export function useNavigation({
|
||||
neighbors,
|
||||
isVideo,
|
||||
mediaContainerRef,
|
||||
videoRef,
|
||||
prevImg,
|
||||
nextImg,
|
||||
togglePlay,
|
||||
}: UseNavigationProps) {
|
||||
const router = useRouter();
|
||||
const wheelCooldownRef = useRef<number>(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]);
|
||||
}
|
||||
Reference in New Issue
Block a user