You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React页面跳转时保持导航栏水平滚动位置的实现方法

横向导航栏跨页面保持X轴滚动位置实现

你已完成滚动位置写入sessionStorage的逻辑,只需补全位置恢复逻辑、修正几个细节问题即可实现需求:

  • 恢复滚动的时机不能选在组件初始挂载阶段:分类数据为异步加载,初始挂载时导航内分类项未渲染、DOM宽度未撑开,此时设置scrollLeft不会生效,需等分类数据加载完成、DOM渲染完毕后再执行恢复
  • 读取存储的滚动值时要做合法性校验,避免非数字值导致滚动逻辑报错
  • 优化存值逻辑:无需通过state中转滚动位置,点击导航项时直接从DOM ref读取实时scrollLeft存入存储即可,避免state异步更新导致存入旧位置;同时移除nav上绑定的onScroll state同步逻辑,减少滚动过程中不必要的组件重渲染
  • 补全「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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 17:58:02