NextJS 14中如何用useRef实现锚点滚动?避免根组件全客户端化
解决方案
核心思路是把需要客户端交互的导航跳转逻辑完全隔离到独立的客户端组件里,让根page.tsx保持为服务器组件,充分保留Next.js的SSR/SSG优势。
步骤1:将Navbar改造为客户端组件
在Navbar.tsx顶部加"use client"声明,把滚动跳转逻辑放在这个组件里,不用跨组件传递ref,直接通过元素ID实现平滑滚动:
"use client"; export default function Navbar() { const scrollToSection = (sectionId: string) => { const section = document.getElementById(sectionId); if (section) { section.scrollIntoView({ behavior: "smooth" }); } }; return ( <nav className="navbar"> <button onClick={() => scrollToSection("about")}>关于我</button> <button onClick={() => scrollToSection("projects")}>作品集</button> <button onClick={() => scrollToSection("contact")}>联系我</button> </nav> ); }
步骤2:根page.tsx保持为服务器组件
根页面不需要加"use client",只负责渲染静态内容和引入Navbar组件,给每个跳转目标区块设置对应ID即可:
import Navbar from "./Navbar"; // 其他静态内容或服务器组件可直接引入,无需客户端声明 export default function Home() { return ( <div className="app-container"> <Navbar /> {/* 关于我区块 */} <section id="about" className="section"> <h2>关于我</h2> {/* 这里放静态或服务器渲染的内容 */} </section> {/* 作品集区块 */} <section id="projects" className="section"> <h2>我的作品集</h2> {/* 作品集列表可引入服务器组件渲染 */} </section> {/* 联系我区块 */} <section id="contact" className="section"> <h2>联系我</h2> {/* 联系信息放这里 */} </section> </div> ); }
为什么这样做?
- 根
page.tsx作为服务器组件,能利用Next.js的SSR/SSG能力,页面内容在服务器生成,加载更快、SEO更好。 - 只有Navbar是客户端组件,仅包含必要的交互逻辑,完全符合Next.js"客户端组件尽可能精简"的建议。
- 用元素ID替代跨组件ref传递,既简化了逻辑,又实现了和之前一样的平滑跳转效果。
可选优化:用Next.js原生API实现跳转
如果想更贴合Next.js生态,也可以用next/navigation的useRouter来实现:
"use client"; import { useRouter } from "next/navigation"; export default function Navbar() { const router = useRouter(); const scrollToSection = (sectionId: string) => { router.push(`#${sectionId}`); // 配合平滑滚动 window.scrollTo({ top: document.getElementById(sectionId)?.offsetTop, behavior: "smooth" }); }; return ( <nav className="navbar"> <button onClick={() => scrollToSection("about")}>关于我</button> <button onClick={() => scrollToSection("projects")}>作品集</button> </nav> ); }
内容的提问来源于stack exchange,提问作者user22842285
相关产品推荐
相关产品推荐

