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

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

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

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

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

对比页面 提供了与 Swiper、Embla、keen-slider 和 react-slick 的完整对比表格。

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

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

融入你自己的设计体系

方块是你自己的组件——图片卡片、圆形头像、文字胶囊——每一个都携带一个 itemId。高度和宽度由你的 CSS 决定;菜单本身不强加任何尺寸。可以借助 单项滚动 像商品滑块一样每次移动一项,也可以显示一个滚动 进度指示器,或者用 RTL 示例 为阿拉伯语、希伯来语商店提供 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 注册表条目就是这条分类栏——shadcn 样式的箭头、拖拽滚动、隐藏滚动条——安装进你的 components/ui/,并由你自己的 tokens 定义样式:

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

相关示例

全部 21 个示例