在Next.js项目中如何实现点击导航滚动到指定组件?
Next.js 同页滚动定位到组件实现方案
下面提供两种可直接落地的实现方式,可根据自己的需求选择:
方案1:原生锚点实现(零额外逻辑,改动最小)
适合不需要自定义滚动偏移、不需要特殊滚动回调的场景:
- 给对应区块组件的最外层DOM添加唯一id,例如About区块加
id="about",Services区块加id="services" - 修改Nav组件中Link的href属性,直接指向对应id的锚点即可:
<li className="nav-item"> <Link href="#about"> <a className="nav-link m-2 p-1 border border-dark pe-auto text-dark">About me</a> </Link> </li> <li className="nav-item"> <Link href="#services"> <a className="nav-link m-2 p-1 border border-dark text-dark">Services</a> </Link> </li>
- 如需平滑滚动效果,在全局CSS中添加如下规则即可:
html { scroll-behavior: smooth; }
如果是跨页面滚动定位,直接把href改成对应页面路由+锚点即可,比如/about#about,Next.js原生支持跳转后自动定位到对应锚点。
方案2:useRef跨组件传递实现(支持自定义滚动逻辑)
适合需要调整滚动偏移(比如fixed导航栏遮挡内容,要减去导航高度)、需要滚动完成后触发回调的场景:
步骤1:父组件定义ref和滚动方法,传递给子组件
修改Index.js代码:
import { useRef } from 'react' import Nav from './Nav' import Services from './Services' import About from './About' export default function Home () { const servicesRef = useRef(null) const aboutRef = useRef(null) const scrollToBlock = (targetRef) => { // 有fixed导航需要偏移的场景 // window.scrollTo({ // top: targetRef.current.offsetTop - 80, // 80替换为你的导航栏实际高度 // behavior: 'smooth' // }) // 不需要偏移直接用scrollIntoView即可 targetRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }) } return ( <> <Nav scrollToBlock={scrollToBlock} aboutRef={aboutRef} servicesRef={servicesRef} /> <About ref={aboutRef} /> <Services ref={servicesRef} /> </> ) }
步骤2:区块组件用forwardRef包裹接收ref
函数组件默认不支持直接接收ref,需要用forwardRef转发,以Services组件为例:
import { forwardRef } from 'react' const Services = forwardRef((props, ref) => { return ( <div ref={ref}> {/* 原Services组件的所有内容 */} </div> ) }) export default Services
步骤3:修改Nav组件调用滚动方法
function Nav ({ scrollToBlock, aboutRef, servicesRef }) { return ( <div> <title>About</title> <ul className="nav justify-content-end m-1 p-1 col-12 pe-auto"> <li className="nav-item"> <a className="nav-link m-2 p-1 border border-dark pe-auto text-dark" onClick={(e) => { e.preventDefault() scrollToBlock(aboutRef) }} href="#" > About me </a> </li> <li className="nav-item"> <a className="nav-link m-2 p-1 border border-dark text-dark" onClick={(e) => { e.preventDefault() scrollToBlock(servicesRef) }} href="#" > Services </a> </li> </ul> </div> ) }
内容的提问来源于stack exchange,提问作者someone
相关产品推荐
相关产品推荐

