"use client"; import { useEffect, useRef, useState } from "react"; import { usePathname, useRouter } from "next/navigation"; /** * 有未保存修改时:关闭/刷新走 beforeunload;站内链接先确认再跳转。 * 未修改时不打扰。hash 分类切换由调用方自行拦截。 */ export default function useUnsavedGuard(dirty: boolean) { const router = useRouter(); const pathname = usePathname(); const dirtyRef = useRef(dirty); dirtyRef.current = dirty; const [pendingHref, setPendingHref] = useState(null); useEffect(() => { const onBeforeUnload = (e: BeforeUnloadEvent) => { if (!dirtyRef.current) return; e.preventDefault(); e.returnValue = ""; }; window.addEventListener("beforeunload", onBeforeUnload); return () => window.removeEventListener("beforeunload", onBeforeUnload); }, []); useEffect(() => { const onClick = (e: MouseEvent) => { if (!dirtyRef.current) return; if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) { return; } const target = e.target; if (!(target instanceof Element)) return; const a = target.closest("a[href]"); if (!a) return; const href = a.getAttribute("href"); if (!href || href.startsWith("#") || href.startsWith("mailto:") || href.startsWith("javascript:")) return; if (a.getAttribute("target") === "_blank") return; let url: URL; try { url = new URL(href, window.location.href); } catch { return; } if (url.origin !== window.location.origin) return; const next = `${url.pathname}${url.search}${url.hash}`; const cur = `${pathname}${window.location.search}${window.location.hash}`; if (next === cur) return; e.preventDefault(); e.stopPropagation(); setPendingHref(next); }; document.addEventListener("click", onClick, true); return () => document.removeEventListener("click", onClick, true); }, [pathname]); const confirmLeave = () => { if (!pendingHref) return; const href = pendingHref; setPendingHref(null); router.push(href); }; return { leaveOpen: pendingHref != null, confirmLeave, cancelLeave: () => setPendingHref(null), }; }