Pro组件、模板与 AI 工具
HeroUI
27.7k

Pagination

Pagination 从 HeroUI v2 到 v3 的迁移指南。

完整的 API 参考、样式指南与高级示例请参阅 v3 Pagination 文档。本指南只关注从 HeroUI v2 的迁移。

结构变化

在 v2 中,Pagination 是单个组件,通过 props 在内部完成所有渲染:

import { Pagination } from "@heroui/react";

export default function App() {
  return (
    <Pagination total={10} initialPage={1} showControls />
  );
}

在 v3 中,Pagination 采用复合组件模式,需要显式组合各个部分:

import { Pagination } from "@heroui/react";

export default function App() {
  return (
    <Pagination>
      <Pagination.Content>
        <Pagination.Item>
          <Pagination.Previous>
            <Pagination.PreviousIcon />
          </Pagination.Previous>
        </Pagination.Item>
        <Pagination.Item>
          <Pagination.Link isActive>1</Pagination.Link>
        </Pagination.Item>
        <Pagination.Item>
          <Pagination.Link>2</Pagination.Link>
        </Pagination.Item>
        <Pagination.Item>
          <Pagination.Link>3</Pagination.Link>
        </Pagination.Item>
        <Pagination.Item>
          <Pagination.Ellipsis />
        </Pagination.Item>
        <Pagination.Item>
          <Pagination.Link>10</Pagination.Link>
        </Pagination.Item>
        <Pagination.Item>
          <Pagination.Next>
            <Pagination.NextIcon />
          </Pagination.Next>
        </Pagination.Item>
      </Pagination.Content>
    </Pagination>
  );
}

主要变化

1. 组件结构

v2: 单个 Pagination 组件,通过 total prop 自动生成页码项
v3: 复合组件:Pagination、Pagination.Summary、Pagination.Content、Pagination.Item、Pagination.Link、Pagination.Previous、Pagination.PreviousIcon、Pagination.Next、Pagination.NextIcon、Pagination.Ellipsis

2. 页码生成

v2: 由 total、siblings、boundaries 等 props 自动生成页码
v3: 手动组合页码项,完全掌控布局与行为;可自行实现分页逻辑或使用分页 hook。

3. Prop 变更

v2 propv3 对应说明
total—已移除(请手动组合条目)
page—通过在 Pagination.Link 上使用 isActive 管理当前页
initialPage—请在外部自行管理状态
onChange—请在各个 Pagination.Link 上使用 onPress
siblings—已移除(请手动组合条目)
boundaries—已移除(请手动组合条目)
dotsJump—已移除(省略号点击请自行处理)
loop—已移除(请自行实现)
showControls—请组合 Pagination.Previous 与 Pagination.Next
isCompact—已移除(请用 Tailwind CSS 控制样式)
showShadow—已移除(请使用 Tailwind shadow-* 类)
sizePagination 上的 size与 v2 相同(sm、md、lg)
variant—已移除(请使用 Tailwind CSS)
color—已移除(请使用 Tailwind CSS)
radius—已移除(请使用 Tailwind CSS)
isDisabledPagination.Link、Pagination.Previous、Pagination.Next 上的 isDisabled按条目分别控制,而非全局
disableCursorAnimation—已移除
disableAnimation—已移除
renderItem—请直接组合子节点
getItemAriaLabel—请在各条目上设置 aria-label
classNames—请在各复合子组件上使用 className

4. Hook 变化

v2: 提供 usePagination hook,便于自定义实现
v3: 无内置 hook——请直接组合分页项,或自行实现分页逻辑

迁移示例

基础分页

import { Pagination } from "@heroui/react";

<Pagination total={10} initialPage={1} />
import { useState } from "react";
import { Pagination } from "@heroui/react";

const [page, setPage] = useState(1);
const totalPages = 10;

<Pagination>
  <Pagination.Content>
    {Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => (
      <Pagination.Item key={p}>
        <Pagination.Link isActive={page === p} onPress={() => setPage(p)}>
          {p}
        </Pagination.Link>
      </Pagination.Item>
    ))}
  </Pagination.Content>
</Pagination>

上一页 / 下一页控件

<Pagination total={10} initialPage={1} showControls />
const [page, setPage] = useState(1);
const totalPages = 10;

<Pagination>
  <Pagination.Content>
    <Pagination.Item>
      <Pagination.Previous
        isDisabled={page === 1}
        onPress={() => setPage((p) => Math.max(1, p - 1))}
      >
        <Pagination.PreviousIcon />
      </Pagination.Previous>
    </Pagination.Item>
    {Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => (
      <Pagination.Item key={p}>
        <Pagination.Link isActive={page === p} onPress={() => setPage(p)}>
          {p}
        </Pagination.Link>
      </Pagination.Item>
    ))}
    <Pagination.Item>
      <Pagination.Next
        isDisabled={page === totalPages}
        onPress={() => setPage((p) => Math.min(totalPages, p + 1))}
      >
        <Pagination.NextIcon />
      </Pagination.Next>
    </Pagination.Item>
  </Pagination.Content>
</Pagination>

含省略号

<Pagination total={20} initialPage={1} siblings={1} boundaries={1} />
const [page, setPage] = useState(1);
const totalPages = 20;

<Pagination>
  <Pagination.Content>
    <Pagination.Item>
      <Pagination.Previous
        isDisabled={page === 1}
        onPress={() => setPage((p) => Math.max(1, p - 1))}
      >
        <Pagination.PreviousIcon />
      </Pagination.Previous>
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Link isActive={page === 1} onPress={() => setPage(1)}>
        1
      </Pagination.Link>
    </Pagination.Item>
    {page > 3 && (
      <Pagination.Item>
        <Pagination.Ellipsis />
      </Pagination.Item>
    )}
    {[page - 1, page, page + 1]
      .filter((p) => p > 1 && p < totalPages)
      .map((p) => (
        <Pagination.Item key={p}>
          <Pagination.Link isActive={page === p} onPress={() => setPage(p)}>
            {p}
          </Pagination.Link>
        </Pagination.Item>
      ))}
    {page < totalPages - 2 && (
      <Pagination.Item>
        <Pagination.Ellipsis />
      </Pagination.Item>
    )}
    <Pagination.Item>
      <Pagination.Link
        isActive={page === totalPages}
        onPress={() => setPage(totalPages)}
      >
        {totalPages}
      </Pagination.Link>
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Next
        isDisabled={page === totalPages}
        onPress={() => setPage((p) => Math.min(totalPages, p + 1))}
      >
        <Pagination.NextIcon />
      </Pagination.Next>
    </Pagination.Item>
  </Pagination.Content>
</Pagination>

仅上一页 / 下一页

{/* v2 无内置的仅 prev/next 模式 */}
const [page, setPage] = useState(1);
const totalPages = 10;

<Pagination>
  <Pagination.Content>
    <Pagination.Item>
      <Pagination.Previous
        isDisabled={page === 1}
        onPress={() => setPage((p) => p - 1)}
      >
        <Pagination.PreviousIcon />
        <span>Previous</span>
      </Pagination.Previous>
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Next
        isDisabled={page === totalPages}
        onPress={() => setPage((p) => p + 1)}
      >
        <span>Next</span>
        <Pagination.NextIcon />
      </Pagination.Next>
    </Pagination.Item>
  </Pagination.Content>
</Pagination>

使用 Pagination.Summary

{/* v2 无内置 summary 插槽 */}
const [page, setPage] = useState(1);
const perPage = 10;
const total = 100;

<Pagination>
  <Pagination.Summary>
    Showing {(page - 1) * perPage + 1}-{Math.min(page * perPage, total)} of {total}
  </Pagination.Summary>
  <Pagination.Content>
    {/* Pagination items */}
  </Pagination.Content>
</Pagination>

自定义图标

{/* v2 需借助 renderItem 才能自定义图标 */}
import { Icon } from "@iconify/react";

<Pagination>
  <Pagination.Content>
    <Pagination.Item>
      <Pagination.Previous onPress={() => setPage((p) => p - 1)}>
        <Pagination.PreviousIcon>
          <Icon icon="gravity-ui:arrow-left" />
        </Pagination.PreviousIcon>
      </Pagination.Previous>
    </Pagination.Item>
    {/* Page links */}
    <Pagination.Item>
      <Pagination.Next onPress={() => setPage((p) => p + 1)}>
        <Pagination.NextIcon>
          <Icon icon="gravity-ui:arrow-right" />
        </Pagination.NextIcon>
      </Pagination.Next>
    </Pagination.Item>
  </Pagination.Content>
</Pagination>

样式变化

v2:classNames prop

<Pagination
  classNames={{
    base: "custom-base",
    wrapper: "custom-wrapper",
    prev: "custom-prev",
    next: "custom-next",
    item: "custom-item",
    cursor: "custom-cursor",
    ellipsis: "custom-ellipsis",
  }}
/>

v3:直接使用 className

<Pagination className="custom-base">
  <Pagination.Content className="custom-wrapper">
    <Pagination.Item className="custom-item">
      <Pagination.Previous className="custom-prev">
        <Pagination.PreviousIcon />
      </Pagination.Previous>
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Link isActive className="custom-cursor">1</Pagination.Link>
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Ellipsis className="custom-ellipsis" />
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Next className="custom-next">
        <Pagination.NextIcon />
      </Pagination.Next>
    </Pagination.Item>
  </Pagination.Content>
</Pagination>

组件剖析

v3 Pagination 的结构如下:

Pagination (Root, nav element)
  ├── Pagination.Summary (optional, info text)
  └── Pagination.Content (ul container)
      └── Pagination.Item (li wrapper, repeated)
          ├── Pagination.Previous (with Pagination.PreviousIcon)
          ├── Pagination.Link (page number, isActive for current)
          ├── Pagination.Ellipsis
          └── Pagination.Next (with Pagination.NextIcon)

总结

  1. 组件结构:由单个自动生成式组件,改为需手动组合的复合组件。
  2. 页码生成:total / siblings / boundaries props → 结合自定义分页逻辑手动渲染页码项。
  3. 当前页:page / initialPage props → 在各个 Pagination.Link 上使用 isActive。
  4. 导航控件:showControls prop → 直接组合 Pagination.Previous 与 Pagination.Next。
  5. 省略号:由自动生成 → 在需要处手动放置 Pagination.Ellipsis。
  6. 事件:单一 onChange → 各 Pagination.Link 上的独立 onPress 处理函数。
  7. 新能力:Pagination.Summary 用于展示结果数量;可通过 PreviousIcon / NextIcon 的 children 自定义图标。
  8. Hook 移除:usePagination → 请自行实现分页逻辑。
  9. 样式 props 移除:variant、color、radius、isCompact、showShadow → 请使用 Tailwind CSS。
  10. classNames 移除:请在各复合子组件上使用 className。

本页目录