如何在同一个按钮上同时使用react router与react scroll功能
解决方案
你原有写法失效的核心原因是嵌套Link组件本质是嵌套<a>标签,不符合HTML规范,两个组件的点击事件会互相冲突。可通过路由判断+react-scroll编程式调用的方式实现需求,具体实现如下:
实现步骤
- 路由逻辑与滚动逻辑分离,通过react-router提供的hooks获取当前路径、执行编程式导航
- 点击导航时判断当前页面:首页直接触发滚动,非首页跳转时携带滚动目标参数
- 首页挂载时监听路由参数,有滚动目标则触发对应滚动行为
完整代码示例
导航组件代码
import { useLocation, useNavigate } from 'react-router-dom'; import { scroller } from 'react-scroll'; // 导航组件内部逻辑 const NavItem = () => { const location = useLocation(); const navigate = useNavigate(); const handleNavClick = (targetSection) => { closeMobileMenu(); // 原有关闭移动端菜单逻辑 if (location.pathname === '/') { // 首页直接滚动到对应模块 scroller.scrollTo(targetSection, { smooth: true, offset: -70, duration: 500, }); } else { // 非首页跳转回首页,携带滚动目标参数 navigate('/', { state: { scrollTo: targetSection } }); } }; return ( <button className='nav-links' onClick={() => handleNavClick('about')} > About </button> ) }
首页组件补充逻辑
import { useEffect } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { scroller, Element } from 'react-scroll'; // 首页组件内部逻辑 const HomePage = () => { const location = useLocation(); const navigate = useNavigate(); useEffect(() => { // 监听到跳转携带的滚动参数时触发滚动 if (location.state?.scrollTo) { scroller.scrollTo(location.state.scrollTo, { smooth: true, offset: -70, duration: 500, }); // 清空路由状态,避免后续进入首页重复滚动 navigate('.', { replace: true, state: {} }); } }, [location, navigate]); return ( <div> {/* 其他首页内容 */} {/* 确保要滚动到的目标模块包裹Element组件,name与滚动目标对应 */} <Element name="about"> {/* 关于模块内容 */} </Element> </div> ) }
注意事项
- 目标滚动模块必须用react-scroll提供的
Element组件包裹,且name属性值与滚动目标参数完全一致 - 如果你的首页路由存在其他别名,同步修改
location.pathname === '/'的判断条件即可 - 可根据需求自行调整scroller的滚动配置项,和原有react-scroll Link的参数保持一致即可
内容的提问来源于stack exchange,提问作者Malek Hammad
相关产品推荐
相关产品推荐

