From 6cc434f103cd47bdbb35b1da59d8b9a1793c1d81 Mon Sep 17 00:00:00 2001 From: freefire Date: Thu, 17 Sep 2026 07:15:52 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BA=A0=E6=AD=A3=E8=BD=AF=E5=AF=BC?= =?UTF-8?q?=E8=88=AA=E5=BE=AE=E6=BB=9A=E6=97=B6=E5=85=AC=E5=BC=80=E9=A1=B5?= =?UTF-8?q?=E5=81=9C=E5=9C=A8=E8=B5=84=E6=96=99=E5=8D=A1=E4=B8=8A=E6=B2=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- frontend/components/SiteChrome.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) 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;