如何在React TypeScript中用useRef+react-scroll实现单页平滑滚动
单页React顶部导航栏平滑滚动实现问题
我正在开发一款单页网站,带有顶部导航栏,功能类似顶部导航平滑滚动的示例网站,但采用React + TypeScript实现。目前已编写NavBar.tsx和App.tsx,其中NavBar.tsx代码如下:
import { Button, Link } from 'react-scroll'; import React from 'react'; import { Link as RouterLink } from 'react-router-dom'; import { useEffect } from 'react'; import { useRef } from 'react'; export interface NavBarProps { events?: string; team?: string; sponsors?: string; contact?: string; corporate?: string; } export default function NavBar(props: NavBarProps) { let myRef: Array<HTMLDivElement> = []; const saveRef = (ref: HTMLDivElement) => { myRef.push(ref); } return ( <ul className="w-full sticky top-0"> <li> <Link className="link inline float-right p-5 hover:bg-yellow-400 text-white" id="navBar" activeClass="active" to={props.events} spy={true} smooth={true} offset={-70} duration={500} ref={saveRef}> Events </Link> <div ref={saveRef}> <Link className="link inline float-right p-5 hover:bg-yellow-400 text-white" id="navBar" activeClass="active" to="projects" spy={true} smooth={true} offset={-70} duration={500} ref={saveRef}> Our Team </Link> </div> <div ref={saveRef}> <Link className="link inline float-right p-5 hover:bg-yellow-400 text-white" id="navBar" activeClass="active" to="blog" spy={true} smooth={true} offset={-70} duration={500} ref={saveRef}> Sponsors </Link> </div> <div ref={saveRef}> <Link className="link inline float-right p-5 hover:bg-yellow-400 text-white" id="navBar" activeClass="active" to="contact" spy={true} smooth={true} offset={-70} duration={500} ref={saveRef}> Contact Us </Link> </div> <div ref={myR}> <Link className="link inline float-right p-5 hover:bg-yellow-400 text-white" id="navBar" activeClass="active" to="section1" spy={true} smooth={true} offset={-70} duration={500} > Corporate </Link> </div> </li> </ul> ) }
(当前为测试版本,部分链接信息不一致;类名较长因使用Tailwind CSS)
我原本用react-scroll的Link实现导航跳转,但不确定如何修改以实现类似示例的平滑滚动效果(导航栏固定在顶部)。App.tsx包含4个导航指向的区块,虽参考过相关教程,但不清楚如何适配React TypeScript。已知react-scroll可实现平滑滚动,但不确定如何与react-router-dom的Link配合,也不知如何正确用useRef获取元素完成该功能。
解决方案
一、修复react-scroll配置实现平滑滚动
你的代码已经配置了smooth={true},但需修正几个问题并确保目标区块匹配:
- 移除重复ID:HTML中
id必须唯一,删除所有重复的id="navBar" - 修正ref错误:代码中
myR未定义,且saveRef会不断向数组push冗余ref,无需给react-scroll的Link或外层div绑定ref - 统一目标ID匹配:确保
Link的to属性值与App.tsx中对应区块的id完全一致
修正后的NavBar.tsx:
import { Link } from 'react-scroll'; import React from 'react'; import { Link as RouterLink } from 'react-router-dom'; export interface NavBarProps { events?: string; team?: string; sponsors?: string; contact?: string; corporate?: string; } export default function NavBar(props: NavBarProps) { return ( <ul className="w-full sticky top-0 bg-white z-50"> {/* 添加背景和层级确保导航栏置顶 */} <li className="flex justify-end"> {/* 用Flex替代float,布局更稳定 */} <Link className="link p-5 hover:bg-yellow-400 text-white" activeClass="active" to={props.events || ''} spy={true} smooth={true} offset={-70} duration={500} > Events </Link> <Link className="link p-5 hover:bg-yellow-400 text-white" activeClass="active" to={props.team || 'projects'} spy={true} smooth={true} offset={-70} duration={500} > Our Team </Link> <Link className="link p-5 hover:bg-yellow-400 text-white" activeClass="active" to={props.sponsors || 'blog'} spy={true} smooth={true} offset={-70} duration={500} > Sponsors </Link> <Link className="link p-5 hover:bg-yellow-400 text-white" activeClass="active" to={props.contact || 'contact'} spy={true} smooth={true} offset={-70} duration={500} > Contact Us </Link> <Link className="link p-5 hover:bg-yellow-400 text-white" activeClass="active" to={props.corporate || 'section1'} spy={true} smooth={true} offset={-70} duration={500} > Corporate </Link> </li> </ul> ) }
二、App.tsx配置目标区块
确保每个需要滚动到的区块都设置对应id:
import NavBar from './NavBar'; function App() { return ( <div className="app"> <NavBar events="events-section" team="team-section" sponsors="sponsors-section" contact="contact-section" corporate="corporate-section" /> {/* 目标滚动区块 */} <div id="events-section" className="min-h-screen">Events Content</div> <div id="team-section" className="min-h-screen">Our Team Content</div> <div id="sponsors-section" className="min-h-screen">Sponsors Content</div> <div id="contact-section" className="min-h-screen">Contact Us Content</div> <div id="corporate-section" className="min-h-screen">Corporate Content</div> </div> ); } export default App;
三、react-scroll与react-router-dom配合使用
区分单页滚动和跨页面跳转场景:
- 单页内滚动:使用
react-scroll的Link - 跨页面路由跳转:使用
react-router-dom的RouterLink
示例:
// 在NavBar中添加首页路由跳转 <RouterLink to="/" className="link p-5 hover:bg-yellow-400 text-white"> Home </RouterLink>
四、手动用useRef实现平滑滚动(可选)
若不想依赖react-scroll,可手动实现:
App.tsx中定义ref和滚动方法:
import { useRef } from 'react'; import NavBar from './NavBar'; function App() { const eventsRef = useRef<HTMLDivElement>(null); const teamRef = useRef<HTMLDivElement>(null); const scrollToSection = (ref: React.RefObject<HTMLDivElement>) => { ref.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }); }; return ( <div className="app"> <NavBar onScrollToEvents={() => scrollToSection(eventsRef)} onScrollToTeam={() => scrollToSection(teamRef)} // 其他区块的回调... /> <div ref={eventsRef} id="events-section" className="min-h-screen">Events Content</div> <div ref={teamRef} id="team-section" className="min-h-screen">Our Team Content</div> {/* 其他区块 */} </div> ); }
- 更新
NavBarProps和组件:
export interface NavBarProps { onScrollToEvents?: () => void; onScrollToTeam?: () => void; // 其他回调... } export default function NavBar(props: NavBarProps) { return ( <ul className="w-full sticky top-0 bg-white z-50"> <li className="flex justify-end"> <button className="link p-5 hover:bg-yellow-400 text-white" onClick={props.onScrollToEvents} > Events </button> <button className="link p-5 hover:bg-yellow-400 text-white" onClick={props.onScrollToTeam} > Our Team </button> {/* 其他按钮 */} </li> </ul> ) }
内容的提问来源于stack exchange,提问作者Saurav Chittal
相关产品推荐
相关产品推荐

