如何用TypeScript实现React头部导航栏吸顶效果?
导航栏吸顶问题修复方案
1. 修正Sticky组件的Props接收逻辑
你的Sticky组件在props处理上存在两处核心错误:一是错误解构了props参数,二是子元素属性名不符合React规范。同时缺少初始滚动状态检测,导致页面刷新时已滚动的场景无法触发吸顶。
修改sticky.tsx:
import React, { useState, useEffect, useRef } from 'react'; import './Sticky.scss'; interface StickyProps { children: React.ReactNode, // 改用React内置的children属性 top: number, } // 正确解构props对象 const Sticky: React.FunctionComponent<StickyProps> = ({ children, top }) => { const [isSticky, setSticky] = useState(false); const ref = useRef<HTMLDivElement>(null); // 添加强类型定义 useEffect(() => { handleScroll(); // 初始调用,处理页面刷新时已滚动的情况 window.addEventListener('scroll', handleScroll); // 移除监听时直接传原函数,避免创建新函数导致无法解绑 return () => { window.removeEventListener('scroll', handleScroll); }; }, [top]); // 依赖top参数,值变化时重新绑定监听 const handleScroll = () => { if (ref.current) { const rect = ref.current.getBoundingClientRect(); setSticky(rect.top <= top); } }; return ( <div className={`sticky__wrapper ${isSticky ? 'sticky' : ''}`} ref={ref}> <div className="sticky--inner"> {children} </div> </div> ); }; export default Sticky
2. 完善Sticky组件的CSS样式
原CSS中核心定位属性被注释,且缺少吸顶后的基础样式,导致视觉上无变化。同时需要处理页面跳动问题。
修改sticky.scss:
.sticky__wrapper { position: relative; /* 设置与导航栏一致的最小高度,避免吸顶时页面跳动 */ min-height: 88px; box-sizing: border-box; } .sticky .sticky--inner { position: fixed; top: 0; /* 取消注释,固定到顶部 */ left: 0; right: 0; z-index: 999; /* 提高层级避免被遮挡 */ background-color: #fff; /* 添加背景色防止内容穿透 */ box-shadow: 0 2px 8px rgba(0,0,0,0.1); /* 可选:添加阴影增强层次感 */ }
3. 调整Header组件的适配样式
确保导航栏在吸顶时能铺满宽度,避免内边距导致布局错位。
修改index.tsx中的HeaderSection:
export const HeaderSection = styled("header")` padding: 1rem 0.5rem; width: 100%; box-sizing: border-box; /* 内边距不影响宽度计算 */ .ant-row-space-between { align-items: center; text-align: center; } `;
4. 正确调用Sticky组件
确保在父组件中正确导入并使用,示例:
import Sticky from './Sticky'; import Header from './Header'; // 页面中使用 <Sticky top={0}> <Header /> </Sticky>
额外性能优化建议
滚动事件会频繁触发,添加防抖处理可以降低性能消耗:
// 自定义防抖函数 const debounce = (func: Function, delay: number) => { let timer: NodeJS.Timeout; return (...args: any[]) => { clearTimeout(timer); timer = setTimeout(() => func(...args), delay); }; }; // 在Sticky组件内部替换handleScroll const debouncedHandleScroll = React.useMemo(() => debounce(handleScroll, 100), [top]); // useEffect中使用防抖后的函数 useEffect(() => { handleScroll(); window.addEventListener('scroll', debouncedHandleScroll); return () => { window.removeEventListener('scroll', debouncedHandleScroll); }; }, [debouncedHandleScroll]);
内容的提问来源于stack exchange,提问作者dodo
相关产品推荐
相关产品推荐

