diff --git a/frontend/components/SiteChrome.tsx b/frontend/components/SiteChrome.tsx index 21c0e7f..cd85cc1 100644 --- a/frontend/components/SiteChrome.tsx +++ b/frontend/components/SiteChrome.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useState } from "react"; +import { useEffect, useLayoutEffect, useRef, useState } from "react"; import { usePathname } from "next/navigation"; import Header from "@/components/Header"; import Footer from "@/components/Footer"; @@ -37,11 +37,25 @@ export default function SiteChrome({ }) { const pathname = usePathname(); const [mounted, setMounted] = useState(false); + const isFirstPath = useRef(true); useEffect(() => { setMounted(true); }, []); + // Next.js App Router:新页顶若仍在视口内会跳过滚顶。sticky Header 把 + // 「微滚后的页顶」判成已可见,软导航就会停在资料卡上沿。父级 layoutEffect + // 晚于 Next.js 子级滚动处理,且不影响 F5 / 带 hash 的定位。 + useLayoutEffect(() => { + if (isFirstPath.current) { + isFirstPath.current = false; + return; + } + if (pathIsAdmin(pathname)) return; + if (window.location.hash) return; + window.scrollTo({ top: 0, left: 0, behavior: "auto" }); + }, [pathname]); + // 首屏跟 SSR;之后在渲染期直接读 pathname,软导航无 Header 闪动 const isAdmin = mounted ? pathIsAdmin(pathname) : initialIsAdmin;