如何让React应用的导航栏跳转首页后滚动到指定元素
解决方案
你可以用React Router内置的state传参能力实现需求,state存在路由内存中,不会暴露在URL里,完全符合你要URL保持静态的要求。
第一步:修改Navbar组件
首先给Navbar增加路由判断逻辑:当前在首页直接滚动,不在首页就跳转首页同时携带要滚动的目标ID:
import { useHistory, useLocation } from 'react-router-dom' export default function Navbar(){ const history = useHistory() const location = useLocation() const handleScroll = (targetId) => { // 当前是首页,直接滚动 if(location.pathname === '/') { const elem = document.getElementById(targetId) elem && elem.scrollIntoView(true) return } // 不是首页,跳首页同时携带滚动目标 history.push('/', { scrollTarget: targetId }) } return( <div className="nav-container"> <nav> <ul className="desktop-nav"> <li> <a className="link-logo" onClick={() => handleScroll('landing-page')} /> </li> <li> <a onClick={() => handleScroll('elem1')}>elem1</a> </li> <li> <a onClick={() => handleScroll('elem2')}>elem2</a> </li> <li> <a onClick={() => handleScroll('elem3')}>elem3</a> </li> </ul> </nav> </div> ); }
第二步:修改首页(SITE/ Home组件)
首页挂载时读取路由state里的滚动目标,执行滚动逻辑:
import { useLocation } from 'react-router-dom' import { useEffect } from 'react' export default function Home(){ const location = useLocation() useEffect(() => { // 读取路由携带的滚动目标 const target = location.state?.scrollTarget if(target) { const elem = document.getElementById(target) // 加短延迟确保DOM已经渲染完成,避免滚动失效 setTimeout(() => { elem && elem.scrollIntoView(true) }, 0) // 可选:清空state避免每次首页刷新都重复滚动 window.history.replaceState({}, document.title) } }, [location.state]) return( <div> <div id='elem1'>elem1</div> <div id='elem2'>elem2</div> <div id='elem3'>elem3</div> <a href='/somewhere'> 跳转至第二页 </a> </div> ); }
补充说明
- 全程URL不会出现任何参数,元素ID完全不会暴露给用户,符合你的要求
- 代码里加了元素存在性判断,避免元素未渲染时触发控制台报错
- 可选的清空state操作可以避免用户刷新首页时重复触发滚动,不需要可以直接删掉。
内容的提问来源于stack exchange,提问作者PlagueDr
相关产品推荐
相关产品推荐

