React页面跳转时保持导航栏水平滚动位置的实现方法
横向导航栏跨页面保持X轴滚动位置实现
你已完成滚动位置写入sessionStorage的逻辑,只需补全位置恢复逻辑、修正几个细节问题即可实现需求:
- 恢复滚动的时机不能选在组件初始挂载阶段:分类数据为异步加载,初始挂载时导航内分类项未渲染、DOM宽度未撑开,此时设置
scrollLeft不会生效,需等分类数据加载完成、DOM渲染完毕后再执行恢复 - 读取存储的滚动值时要做合法性校验,避免非数字值导致滚动逻辑报错
- 优化存值逻辑:无需通过state中转滚动位置,点击导航项时直接从DOM ref读取实时
scrollLeft存入存储即可,避免state异步更新导致存入旧位置;同时移除nav上绑定的onScrollstate同步逻辑,减少滚动过程中不必要的组件重渲染 - 补全「All Products」导航项的点击存值事件,当前该入口点击跳转时不会触发存值逻辑
修改后完整代码
export function Navigation({ className }) { const ref = React.useRef() const { loading, error, data } = useQuery(GET_CATEGORIES_QUERY) const handleClickedNavItem = () => { if (ref.current) { sessionStorage.setItem("navScrollX", ref.current.scrollLeft) } } React.useEffect(() => { // DOM未就绪、分类数据未加载完成时不执行 if (!ref.current || !data) return const savedPos = sessionStorage.getItem("navScrollX") const scrollX = Number(savedPos) // 校验为有效数字时才设置滚动位置 if (!Number.isNaN(scrollX)) { ref.current.scrollLeft = scrollX } }, [data]) if (loading) { return <Toast show={loading}>Loading..</Toast> } return ( <> {!loading && ( <nav id="nav-id" className={[navStyle, className].join(" ")} ref={ref} > <Link key="All" className={navLink} to="/products/" activeClassName={activeLink} onClick={handleClickedNavItem} > All Products </Link> {data.productCategories.nodes.map((category, i) => ( <Link onClick={handleClickedNavItem} key={category.name} className={navLink} to={`/products/${category.slug}`} activeClassName={activeLink} replace onMouseEnter={() => { client.query({ query: GET_PRODUCTS_FROM_SLUG, variables: { slug: category.slug }, }) }} > {category.name} </Link> ))} </nav> )} </> ) }
如果需要调整滚动体验,可以把直接赋值scrollLeft换成scrollTo方法配置滚动行为:
ref.current.scrollTo({ left: scrollX, behavior: 'instant' // 页面刚加载时用instant避免滚动动画突兀,需要动画就换成smooth })
内容的提问来源于stack exchange,提问作者haulvulgar
相关产品推荐
相关产品推荐

