ProComponents, templates & AI tooling
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: 复合组件:PaginationPagination.SummaryPagination.ContentPagination.ItemPagination.LinkPagination.PreviousPagination.PreviousIconPagination.NextPagination.NextIconPagination.Ellipsis

2. 页码生成

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

3. Prop 变更

v2 propv3 对应说明
total已移除(请手动组合条目)
page通过在 Pagination.Link 上使用 isActive 管理当前页
initialPage请在外部自行管理状态
onChange请在各个 Pagination.Link 上使用 onPress
siblings已移除(请手动组合条目)
boundaries已移除(请手动组合条目)
dotsJump已移除(省略号点击请自行处理)
loop已移除(请自行实现)
showControls请组合 Pagination.PreviousPagination.Next
isCompact已移除(请用 Tailwind CSS 控制样式)
showShadow已移除(请使用 Tailwind shadow-* 类)
sizePagination 上的 size与 v2 相同(smmdlg
variant已移除(请使用 Tailwind CSS)
color已移除(请使用 Tailwind CSS)
radius已移除(请使用 Tailwind CSS)
isDisabledPagination.LinkPagination.PreviousPagination.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.PreviousPagination.Next
  5. 省略号:由自动生成 → 在需要处手动放置 Pagination.Ellipsis
  6. 事件:单一 onChange → 各 Pagination.Link 上的独立 onPress 处理函数。
  7. 新能力Pagination.Summary 用于展示结果数量;可通过 PreviousIcon / NextIcon 的 children 自定义图标。
  8. Hook 移除usePagination → 请自行实现分页逻辑。
  9. 样式 props 移除variantcolorradiusisCompactshowShadow → 请使用 Tailwind CSS。
  10. classNames 移除:请在各复合子组件上使用 className

本页目录