Cadenza
EN

DataPagination

offset 分页条 —— page / limit 独立受控,零文案设计,i18n 留在业务层

offset 分页条:左侧摘要、右侧「每页条数选择器 + 页码指示 + 四个导航按钮」。 组件自己不产出任何可见文案 —— 页码指示默认是语言中立的 3 / 13,摘要、 「每页」标签由外部注入,i18n 天然留在业务层。aria-label 有英文兜底(四个导航 按钮,以及每页选择器在不传 rowsPerPageLabel 时的 'Rows per page'), 从业务层传译文即可覆盖。

使用

import { DataPagination } from '@gedatou/cadenza-ui'
<DataPagination
  defaultLimit={20}
  summary={({ total }) => `共 ${total} 条`}
  total={137}
/>

非受控:只给 total 和初始值,组件自持状态。summarypageIndicator 都是渲染函数,收到同一个 DataPaginationState{ page, limit, total, totalPages }

受控

分页状态提到组件外,数据切片跟着状态走。改 limit 时记得把 page 归 1 (旧页码在新页数下可能越界)。与 DataTable 组合就是这个形状:

pagelimit 各自支持受控 / 非受控(useControllableState 语义:传 page 即受控,传 defaultPage 即非受控,两者互不影响)。

自定义文案

pageIndicator 换掉默认页码指示;summary 里能算出区间;四个导航按钮的 aria-label 从业务层传译文;limitOptions={[]} 去掉每页条数选择器(用缺席表达,不开渲染开关):

内建守卫

  • total = 0 视为「数据未加载完」,不触发页码钳位 —— react-query 切换查询时数据会短暂变 undefined,此时钳位会把一个过期页码闪进 URL 同步的调用方。
  • 数据已加载且 page 越界时自动钳回最后一页(删光最后一页的行、 调大 limit 后都会发生)。
  • limit 为 0 / NaN(比如从 URL 参数解析而来)时总页数按 1 兜底, 不会出现 1 / Infinity 和 NaN 按钮。

钳位走的是和点击同一条回调:onPageChange 会拿到 reason: 'missing'eventDetailscancel() 同样能拒绝它。

Headless:useDataPaginationState

分页状态本身单独导出(useXxxState 风格)。入参就是 Props 表里的 状态切片(DataPaginationStateOptions),返回 DataPaginationStateResultpage / limit / totalPages / setPage / setLimit / canPrevious / canNext —— 零与 NaN 守卫、越界钳位同样生效。不渲染我们这个分页条、 自己画分页 UI 时用它:

import { useDataPaginationState } from '@gedatou/cadenza-ui'
 
const { page, setPage, canNext } = useDataPaginationState({
  total: 137,
  defaultLimit: 20,
})

setPage / setLimit 都接 SetStateActionsetPage(p => p + 1)), 第二参是可选的 eventDetails,不传时 reason'none'

什么时候用 DataPagination

数页码的 offset 分页才用它。游标分页不数页码,也就没有「第几页 / 共几页」可显示 —— 走 DataTable 的列表状态 props (hasNextPage / onLoadMore),弹层里的长列表同理,见 InfiniteSelect

状态与 className

分页条是纯 DOM 结构,自己不挂状态属性 —— 导航按钮的不可用是真实的 disabledcanPrevious / canNext 为假时),按状态改样式就用它。className 是普通字符串,只落在根元素;没有 ...rest 透传,其余属性到不了 DOM。

内部部件各带一个 data-slot,需要从外部定位时当选择器用:

data-slot是什么
data-pagination根元素,className 的落点
data-pagination-summary左侧摘要;不传 summary 时换成一个不带 slot 的空占位 div,把右侧顶到右边
data-pagination-limit每页条数选择器的触发器
data-pagination-indicator页码指示

键盘交互

控件都是原生语义:

按键效果
Tab依次落到每页条数选择器与四个导航按钮;不可用的按钮是真实 disabled,直接跳过
Enter / Space触发当前聚焦的导航按钮
方向键 / Enter / Esc每页条数是本库的 Select:方向键选择、Enter 确认、Esc 关闭

Props

顺序规则:必填 → 非受控默认值 → 受控值 → 回调 → 行为开关 → 外观 → className

Prop类型默认值说明
totalnumber总条数;0 视为未加载完,不触发钳位
page / defaultPage / onPageChangenumber1页码(受控 / 非受控)。回调第二参是 DataPaginationChangeEventDetailsreason'item-press'(条内控件)/ 'missing'(越界钳位)/ 'none'(程序化 setPage),cancel() 拒绝这次变更
limit / defaultLimit / onLimitChangenumber20每页条数(受控 / 非受控),回调同上
limitOptionsnumber[][10, 20, 50, 100]每页条数选项;[] 整个选择器不渲染
summary(state) => ReactNode左侧摘要;不传则该槽位收起
rowsPerPageLabelstring选择器前的可见标签(不传则不渲染),同时作为选择器的 aria-label;不传时 aria-label 兜底英文 'Rows per page'。是 string 不是 ReactNode——要富文本的内容走组合通道,一个「每页」标签不属于那种
pageIndicator(state) => ReactNodepage / totalPages页码指示
firstPageLabel / previousPageLabel / nextPageLabel / lastPageLabelstring'First page'四个图标按钮的 aria-label,从业务层传译文
classNamestring根元素类名

state 即导出的 DataPaginationState{ page, limit, total, totalPages }DataPaginationPropsDataPaginationStateOptions / DataPaginationStateResultheadless hook 的入参与返回值)、 DataPaginationChangeEventReason / DataPaginationChangeEventDetails 也一并导出。