react-router-dom路由跳转后页面未自动滚动到顶部如何解决?
解决方案
你之前的方案失效核心有三个原因:
- 封装的ScrollToTop组件存在拼写错误:返回的清理函数里把
unlisten写成了unlist,导致监听器没有正常工作 - 滚动逻辑没有兼容不同浏览器的滚动载体差异,部分浏览器的滚动生效节点是body而非documentElement
- 如果你的页面滚动容器是自定义的
overflow: auto内部节点,直接调用window.scrollTo默认不会生效
1. 修正ScrollToTop组件代码
import { useEffect } from 'react'; import { withRouter } from 'react-router-dom'; function ScrollToTop({ history }) { useEffect(() => { const unlisten = history.listen(() => { // 兼容多浏览器根节点滚动 window.scrollTo(0, 0); document.documentElement.scrollTop = 0; document.body.scrollTop = 0; // 如果使用自定义滚动容器,补充下方逻辑,替换为你的容器类名/id即可 // document.querySelector('.main-content').scrollTop = 0 }); return () => { unlisten(); // 修正拼写错误 } }, [history]); return null; } export default withRouter(ScrollToTop);
2. 全局挂载组件
将组件放在Router组件内部的最顶层,确保所有路由变化都能被监听到:
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; import ScrollToTop from './components/ScrollToTop'; function App() { return ( <Router> <ScrollToTop /> {/* 必须放在Router内部,所有路由组件上层 */} <Switch> <Route exact path="/" component={首页组件} /> <Route path="/shopping cart" component={购物车组件} /> {/* 其余路由配置 */} </Switch> </Router> ); }
类组件兼容方案
如果你不想单独封装函数组件,也可以在根路由组件的componentDidUpdate中添加路由变化判断逻辑:
// 注意当前组件需要先用withRouter包裹,才能拿到location属性 componentDidUpdate(prevProps) { if (this.props.location.pathname !== prevProps.location.pathname) { window.scrollTo(0, 0); document.documentElement.scrollTop = 0; document.body.scrollTop = 0; } }
react-router-dom v6兼容提示
如果后续升级到v6版本,withRouter已被移除,可以用以下方式实现:
import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; const ScrollToTop = () => { const { pathname } = useLocation(); useEffect(() => { window.scrollTo(0, 0); document.documentElement.scrollTop = 0; document.body.scrollTop = 0; }, [pathname]); return null; }
挂载方式和v5版本一致,放在Router内部顶层即可。
内容的提问来源于stack exchange,提问作者Joppe Meijers
相关产品推荐
相关产品推荐

