---
title: "面向电商的 React 分类栏"
description: "React 中的横向分类栏：原生滚动、到达边缘时箭头自动禁用、逐项可见性检测支持图片懒加载和数据分析。附带演示和源码。"
canonical: "https://react-horizontal-scrolling-menu.dev/zh-cn/category-rail"
image: "https://react-horizontal-scrolling-menu.dev/og.png"
---

# React 中面向你的商店的分类栏

分类栏——位于店铺商品网格上方、可点击的部门分类行——是电商场景中流量最高的滚动容器，而它们本质是菜单，不是轮播图：每个方块都是一个链接，没有吸附对齐，而边缘处露出半个方块正是在邀请用户继续滚动。

TTokyo

OOslo

LLima

CCairo

SSydney

QQuito

SSeoul

PPorto

DDenver

HHanoi

拖拽这一栏，或使用箭头——它们会在该行真正的端点处禁用。

[在 Storybook 中实时编辑此示例](https://asmyshlyaev177.github.io/react-horizontal-scrolling-menu/?path=/story/examples-simple--simple)

## 为什么原生滚动在店铺页面上更胜一筹

店铺分类栏位于首屏之内，而首屏正是你为每一分 Lighthouse 分数拼尽全力的地方。轮播引擎需要用几十 KB 的手势模拟代码，去实现浏览器原生就能做到的事；本库压缩后（min+gzip）大约只有 ≈5.7 kB，并把滚动完全交给平台处理，因此没有 hydration 卡顿——这一栏在你的 JavaScript 加载完成之前就能滚动，也就意味着它在爬虫看到的服务端渲染 HTML 中同样可用。这个页面本身就是服务端渲染的证明：上方的演示在禁用 JavaScript 的情况下依然可以滚动。

[对比页面](https://react-horizontal-scrolling-menu.dev/zh-cn/compare.md) 提供了与 Swiper、Embla、keen-slider 和 react-slick 的完整对比表格。

## 可见性跟踪是一项店铺场景功能

逐项可见性听起来像是一个实现细节，直到你把它对应到商品运营场景：

-   **懒加载图片**——在 `useIsVisible` 报告该方块进入屏幕之前，先渲染一个占位方块。
-   **曝光分析**——`getVisible()`（在首页的 [首屏演示](https://react-horizontal-scrolling-menu.dev/zh-cn.md) 中实时运行）能准确告诉你哪些分类被用户看到过，而不只是知道这一栏被渲染过。
-   **边缘感知箭头**——即便分类是异步加载进来的，也能在真正的端点处禁用或隐藏，如 [新增项目示例](https://react-horizontal-scrolling-menu.dev/zh-cn/examples/add-items.md) 所示。

## 融入你自己的设计体系

方块是你自己的组件——图片卡片、圆形头像、文字胶囊——每一个都携带一个 `itemId`。高度和宽度由你的 CSS 决定；菜单本身不强加任何尺寸。可以借助 [单项滚动](https://react-horizontal-scrolling-menu.dev/zh-cn/examples/one-item-scroll.md) 像商品滑块一样每次移动一项，也可以显示一个滚动 [进度指示器](https://react-horizontal-scrolling-menu.dev/zh-cn/examples/progress.md)，或者用 [RTL 示例](https://react-horizontal-scrolling-menu.dev/zh-cn/examples/rtl.md) 为阿拉伯语、希伯来语商店提供 RTL 支持——这条分类栏是组合出来的，而不是配置出来的。

## 最简模式

带有 `itemId` 的方块，箭头来自可见性 hooks——整条分类栏的代码不到四十行。

CategoryRail.tsx

```
function CategoryRail({ categories }: { categories: Category[] }) {
  return (
    <ScrollMenu LeftArrow={LeftArrow} RightArrow={RightArrow}>
      {categories.map((category) => (
        <CategoryTile itemId={category.id} key={category.id} {...category} />
      ))}
    </ScrollMenu>
  );
}

function CategoryTile({ itemId, name, image }: CategoryTileProps) {
  // Lazy images for free: placeholders until the tile is on screen.
  const visibility = React.useContext<publicApiType>(VisibilityContext);
  const isVisible = visibility.useIsVisible(itemId, false);
  return (
    <a href={`/category/${itemId}`} className="rail-tile">
      {isVisible ? <img src={image} alt="" /> : <div className="ph" />}
      <span>{name}</span>
    </a>
  );
}

function LeftArrow() {
  const visibility = React.useContext<publicApiType>(VisibilityContext);
  const atStart = visibility.useLeftArrowVisible();
  return (
    <button disabled={atStart} onClick={() => visibility.scrollPrev()}>
      ←
    </button>
  );
}
```

## 或者以 shadcn 组件的形式安装

基础的 [scroll-menu](https://react-horizontal-scrolling-menu.dev/r/scroll-menu.json) 注册表条目就是这条分类栏——shadcn 样式的箭头、拖拽滚动、隐藏滚动条——安装进你的 `components/ui/`，并由你自己的 tokens 定义样式：

shadcn

```
npx shadcn@latest add https://react-horizontal-scrolling-menu.dev/r/scroll-menu.json
```

## 相关示例

-   [快速入门最小菜单：项目、两个箭头，开箱即用的可见性。](https://react-horizontal-scrolling-menu.dev/zh-cn/examples/simple.md)
-   [一次滚动一个项目箭头一次前进一个项目，而非一整页。](https://react-horizontal-scrolling-menu.dev/zh-cn/examples/one-item-scroll.md)
-   [滚动进度指示器由可见项目驱动的进度条。](https://react-horizontal-scrolling-menu.dev/zh-cn/examples/progress.md)

[全部 21 个示例](https://react-horizontal-scrolling-menu.dev/zh-cn/examples.md)

---

More examples: <https://react-horizontal-scrolling-menu.dev/examples.md>
Library summary for LLMs: <https://react-horizontal-scrolling-menu.dev/llms.txt>
