迁移React项目后Jquery滚动函数报错:Cannot read properties of undefined (reading 'top')
解决React迁移中滚动功能报错:Cannot read properties of undefined (reading 'top')
问题根源
你遇到的报错是因为jQuery执行时目标section元素还未被React渲染到DOM中,导致$('#section_' + value)返回空集合,调用.offset()得到undefined,进而访问.top时触发报错。另外,在React项目中混合使用jQuery操作DOM,会和React的虚拟DOM管理机制冲突,容易出现渲染不同步、事件失效等问题。
解决方案:改用React原生方式实现滚动功能
完全移除原有的jQuery脚本,用React的hooks(useRef、useState、useEffect)来实现滚动监听和锚点滚动功能,以下是完整实现:
1. 完整TSX组件代码
import { useState, useEffect, useRef } from 'react'; const App = () => { // 保存所有section的ref const sectionRefs = { section_1: useRef<HTMLElement>(null), section_2: useRef<HTMLElement>(null), section_3: useRef<HTMLElement>(null), }; // 管理当前激活的导航索引 const [activeIndex, setActiveIndex] = useState(0); // 导航项配置 const navItems = [ { label: 'Home', target: 'section_1' }, { label: 'About', target: 'section_2' }, { label: 'Ecosystem', target: 'section_3' }, ]; // 滚动监听逻辑 useEffect(() => { const handleScroll = () => { const scrollTop = window.scrollY; // 遍历所有section,判断当前滚动位置对应的激活项 Object.entries(sectionRefs).forEach(([key, ref], index) => { if (ref.current) { const offsetTop = ref.current.offsetTop - 83; // 当滚动位置超过section的偏移量时,设置为激活项 if (scrollTop + 1 >= offsetTop) { setActiveIndex(index); } } }); }; // 添加滚动事件监听 window.addEventListener('scroll', handleScroll); // 组件卸载时移除监听,避免内存泄漏 return () => window.removeEventListener('scroll', handleScroll); }, []); // 点击导航滚动到对应section的逻辑 const handleNavClick = (e: React.MouseEvent<HTMLAnchorElement>, targetKey: string) => { e.preventDefault(); const targetRef = sectionRefs[targetKey as keyof typeof sectionRefs].current; if (targetRef) { // 计算滚动目标位置 const targetScrollTop = targetRef.offsetTop - 83; window.scrollTo({ top: targetScrollTop, behavior: 'smooth', // 平滑滚动,替代jQuery的animate }); } }; return ( <div> {/* 导航栏 */} <nav className="navbar navbar-expand-lg"> <div className="container"> <div className="collapse navbar-collapse" id="navbarNav"> <ul className="navbar-nav align-items-lg-center ms-auto me-lg-5"> {navItems.map((item, index) => ( <li className="nav-item" key={item.target}> <a className={`nav-link click-scroll ${index === activeIndex ? 'active' : 'inactive'}`} href={`#${item.target}`} onClick={(e) => handleNavClick(e, item.target)} > {item.label} </a> </li> ))} </ul> </div> </div> </nav> {/* 各个section */} <section ref={sectionRefs.section_1} className="home-section section-padding" id="section_1"> {/* 这里填入Home区块内容 */} </section> <section ref={sectionRefs.section_2} className="about-section section-padding" id="section_2"> {/* 这里填入About区块内容 */} </section> <section ref={sectionRefs.section_3} className="ecosystem-section section-padding" id="section_3"> {/* 这里填入Ecosystem区块内容 */} </section> </div> ); }; export default App;
2. 关键改进点说明
- 用
useRef获取DOM元素:直接在React组件中绑定section的ref,确保能准确获取到渲染后的真实DOM元素,彻底避免jQuery找不到元素的问题。 useEffect管理滚动事件:在组件挂载后添加滚动监听,卸载时移除,符合React的生命周期,避免内存泄漏。useState管理激活状态:通过状态更新导航项的active/inactive类,完全遵循React的数据流,避免直接操作DOM带来的同步问题。- 原生平滑滚动:用
window.scrollTo配合behavior: 'smooth'替代jQuery的animate,无需依赖外部库,更符合React生态。
3. 额外注意事项
- 移除原HTML中的jQuery脚本和相关逻辑,避免和React代码冲突。
- 如果section是异步加载的(比如从接口获取内容后渲染),需要在
useEffect的依赖数组中添加对应的加载状态,确保监听逻辑在组件完全加载完成后执行。
内容的提问来源于stack exchange,提问作者Migk
相关产品推荐
相关产品推荐

