分页
概述
分页用于将内容或数据拆分为多个页面,并提供用于跳转到上一页/下一页的导航控件。
特性
- 数据驱动的 Compact 组合 —
SPagination将整体结构委托给 Aria 的PaginationCompact,由它负责页码窗口计算、默认内容和内部组合(root → list → 页码项/操作按钮 → 省略号)。 - 受控/非受控页码状态 —
page/pageSize支持v-model(受控);defaultPage/defaultPageSize提供非受控用法,底层基于useControllableState。 - 智能页码窗口 —
siblingCount控制当前页两侧显示的页码按钮数量;showEdges: true时始终固定首页与末页,并根据当前页位置自动渲染单个或双省略号。 - 边界自动禁用 — 第一页时 prev/first 禁用、最后一页时 next/last 禁用;
disabled: true会禁用整个控件并抑制所有交互。 - 四种视觉变体 —
variant(pure/solid/outline/soft)、shape(rounded/square)与size(xs…2xl)通过paginationVariants的scv()配方应用。 actionVariant— 开启后,first/prev/next/last 操作按钮也套用当前variant样式;该样式默认只作用于选中页码。- 八个自定义插槽 —
default(列表)、leading、trailing、first、prev、next、last、ellipsis;动态插槽转发保证样式包装器可触达所有 Aria 插槽。 - 分区属性转发 —
listProps、listItemProps、ellipsisProps、firstProps、prevProps、nextProps、lastProps可将属性转发到对应区域。 - 完整 ARIA 语义 — 根元素为
nav;当前页带有aria-current="page"与选中态属性;每个按钮都有本地化的aria-label。 - 本地化无障碍文案 — 操作按钮文案与页码标签模板来自 locale 注册表(
pageLabel支持{value}占位符),内置 13 种语言。 - RTL 支持 — 操作按钮图标通过
rtl:[&>svg]:rotate-180自动镜像。 - Aria 组合 —
PaginationRoot/PaginationList/PaginationListItem/PaginationEllipsis/PaginationFirst/PaginationPrev/PaginationNext/PaginationLast均可从@vean/aria/pagination导入,用于完全自定义样式构建。
用法
SPagination将页码窗口计算委托给 Aria 的PaginationCompact。如需无样式、数据驱动的组合,请从@vean/aria/pagination导入PaginationCompact。
演示
基础
插槽
You can use the slot to customize the first, prev, next, and last buttons
操作
When actionVariant is true, the action button will use the variant styling
显示
When showFirstOrLast is false, the first and last buttons will not be shown
API
Aria 层
11Pagination
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
class | ClassValue | — | 应用于根元素的额外类名。 |
ui | Partial<PaginationUi> | — | 自定义 UI 类名 |
size | ThemeSize | — | 分页的大小 |
variant | PaginationVariant | — | 分页的变体 |
shape | PaginationShape | — | 分页的样式 |
actionVariant | boolean | — | “第一页”、“上一页”、“下一页”和“最后一页”操作按钮是否也使用 `variant` 样式(该样式通常仅用于当前页面) |
showFirstOrLast | boolean | — | 是否显示“第一”或“最后”。 |
listProps | PaginationListProps | — | 转发给列表元素的属性。 |
listItemProps | PaginationListItemProps | — | 转发给列表项元素的属性。 |
ellipsisProps | PaginationEllipsisProps | — | 转发给省略号元素的属性。 |
firstProps | PaginationButtonProps | — | 转发给第一个元素的属性。 |
prevProps | PaginationButtonProps | — | 转发给前一个元素的属性。 |
nextProps | PaginationButtonProps | — | 属性将转发给下一个元素。 |
lastProps | PaginationButtonProps | — | 属性将转发给最后一个元素。 |
page | number | — | 当前页面的受控值。可绑定为 `v-model:page`。 |
defaultPage | number | — | 页面初次渲染时应处于活动的值。当不需要控制该值的状态时使用
state。 |
pageSize | number | — | 每页条目数 |
defaultPageSize | number | 10 | 初始渲染时 `pageSize` 的默认值。当无需控制该值的状态时使用。 |
total | number | — | 列表中的项目数量 |
siblingCount | number | — | 应在当前页面周围显示同级文档的数量 |
disabled | boolean | — | 当值为 `true` 时,禁止用户与该项进行交互 |
showEdges | boolean | — | 当值为 `true` 时,始终显示首页、末页和省略号 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:page | number | 页面值发生变化时触发的事件处理程序 |
update:pageSize | number | 当页面大小值发生变化时调用的事件处理程序 |
插槽
| 插槽名 | 参数 | 描述 |
|---|---|---|
leading | — | 为首行位置提供自定义内容。 |
trailing | — | 尾部槽位的自定义内容。 |
first | — | 第一个插槽的自定义内容。 |
prev | — | prev 槽位的自定义内容。 |
next | — | 下一个插槽的自定义内容。 |
last | — | 最后一个位置的自定义内容。 |
ellipsis | — | 省略号位置的自定义内容。 |
PaginationButton
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
type | ButtonType | 'button' | 按钮元素的类型。可以是 'button'、'submit' 或 'reset' 之一。 |
disabled | boolean | — | 该组件是否已禁用。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
PaginationCompact
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
showFirstOrLast | boolean | — | 是否显示“第一”或“最后”。 |
listProps | PaginationListProps | — | 转发给列表元素的属性。 |
listItemProps | PaginationListItemProps | — | 转发给列表项元素的属性。 |
ellipsisProps | PaginationEllipsisProps | — | 转发给省略号元素的属性。 |
firstProps | PaginationButtonProps | — | 转发给第一个元素的属性。 |
prevProps | PaginationButtonProps | — | 转发给前一个元素的属性。 |
nextProps | PaginationButtonProps | — | 属性将转发给下一个元素。 |
lastProps | PaginationButtonProps | — | 属性将转发给最后一个元素。 |
page | number | — | 当前页面的受控值。可绑定为 `v-model:page`。 |
defaultPage | number | — | 页面初次渲染时应处于活动的值。当不需要控制该值的状态时使用
state。 |
pageSize | number | — | 每页条目数 |
defaultPageSize | number | 10 | 初始渲染时 `pageSize` 的默认值。当无需控制该值的状态时使用。 |
total | number | — | 列表中的项目数量 |
siblingCount | number | — | 应在当前页面周围显示同级文档的数量 |
disabled | boolean | — | 当值为 `true` 时,禁止用户与该项进行交互 |
showEdges | boolean | — | 当值为 `true` 时,始终显示首页、末页和省略号 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:page | number | 页面值发生变化时触发的事件处理程序 |
update:pageSize | number | 当页面大小值发生变化时调用的事件处理程序 |
插槽
| 插槽名 | 参数 | 描述 |
|---|---|---|
leading | — | 为首行位置提供自定义内容。 |
trailing | — | 尾部槽位的自定义内容。 |
first | — | 第一个插槽的自定义内容。 |
prev | — | prev 槽位的自定义内容。 |
next | — | 下一个插槽的自定义内容。 |
last | — | 最后一个位置的自定义内容。 |
ellipsis | — | 省略号位置的自定义内容。 |
PaginationEllipsis
PaginationFirst
PaginationLast
PaginationList
PaginationListItem
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
value | number | — | 页面值 |
type | ButtonType | 'button' | 按钮元素的类型。可以是 'button'、'submit' 或 'reset' 之一。 |
disabled | boolean | — | 该组件是否已禁用。 |
asChild | boolean | — | 将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。 |
as | AsTag | Component | 'div' | 该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。 |
PaginationNext
PaginationPrev
PaginationRoot
属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
page | number | — | 当前页面的受控值。可绑定为 `v-model:page`。 |
defaultPage | number | — | 页面初次渲染时应处于活动的值。当不需要控制该值的状态时使用
state。 |
pageSize | number | — | 每页条目数 |
defaultPageSize | number | 10 | 初始渲染时 `pageSize` 的默认值。当无需控制该值的状态时使用。 |
total | number | — | 列表中的项目数量 |
siblingCount | number | — | 应在当前页面周围显示同级文档的数量 |
disabled | boolean | — | 当值为 `true` 时,禁止用户与该项进行交互 |
showEdges | boolean | — | 当值为 `true` 时,始终显示首页、末页和省略号 |
事件
| 事件名 | 参数 | 描述 |
|---|---|---|
update:page | number | 页面值发生变化时触发的事件处理程序 |
update:pageSize | number | 当页面大小值发生变化时调用的事件处理程序 |
备注
架构与竞品对比
| 关注点 | SoybeanUI | shadcn-vue Pagination | Ant Design Pagination | Element Plus Pagination |
|---|---|---|---|---|
| Aria / 样式双层分离 | ✅ @vean/aria/pagination + scv() | ❌ 单一包 | ❌ 单一包 | ❌ 单一包 |
| 数据驱动 Compact API | ✅ PaginationCompact + 8 个类型化插槽 | ✅ Pagination + PaginationItem 部件 | ✅ 配置驱动(total, current) | ✅ layout / components |
| 受控/非受控 | ✅ page/defaultPage、pageSize/defaultPageSize | ✅ v-model | ✅ current / defaultCurrent | ✅ v-model |
| 省略号与固定首尾页 | ✅ showEdges + 自动单/双省略号 | ✅ PaginationItem 的 showEdges | ✅ showLessItems / 自动省略号 | ✅ pager-count |
| 边界自动禁用 | ✅ 第一页禁用 prev/first,末页禁用 next/last | ✅ 部件级 disabled | ✅ prevIcon/nextIcon 处理 | ✅ 自动 |
| 整体禁用 | ✅ disabled | ✅ | ✅ disabled | ✅ disabled |
| 选中页样式 | ✅ data-[selected] + actionVariant | ✅ data-[active] | ✅ current 项 class | ✅ active |
本地化 aria-label | ✅ locale 注册表(13 种语言,{value} 插值) | 硬编码 / aria-label prop | 部分支持 | — |
| 变体系统 | ✅ pure/solid/outline/soft × rounded/square × xs…2xl | ✅ 仅尺寸 | ✅ size | ✅ small/default/large |
| 分区属性转发 | ✅ 7 组 props | ✅ 部件级 asChild | ✅ itemRender | ✅ 分区 props |
| RTL 图标镜像 | ✅ 自动 | — | ✅ | ✅ |
运行时注意事项
- 窗口数学 —
getRange仅当当前页远离两端时(leftSiblingIndex > firstPageIndex + 2且rightSiblingIndex < lastPageIndex - 2)才显示双省略号;靠近任一端时退化为单个省略号,否则渲染完整范围。 total页数 —pageCount为Math.max(1, Math.ceil(total / pageSize)),空列表也至少有一页;page超过pageCount时渲染最后一个窗口且不会崩溃。- 受控状态同步 — 使用
v-model:page绑定时,点击页码会发出update:page;内部窗口跟随 prop,因此外部页码变化(如数据请求后)会自动重新渲染正确窗口。 showFirstOrLast— 设为false时移除 first/last 按钮但保留 prev/next;页数计算不受影响。actionVariant— 仅让操作按钮复用variant配方;选中页码始终使用data-[selected]样式,与该开关无关。- Locale 回退 — 按钮文案来自
useLocaleMessages;缺失的 key 回退到默认英文包;pageLabel通过interpolate支持{value}占位符。 - 无障碍输出 — 当前页带有
aria-current="page"与data-selected属性;禁用的操作按钮保留disabled,因此会被辅助技术与键盘导航跳过。
FAQ
省略号什么时候出现?
showEdges: true 时,首页与末页始终固定。当前页位于窗口任一端 → 单个省略号;深居中间(如 100 页中的第 50 页)→ 双省略号,两侧各有 siblingCount 个页码。showEdges: false 时只渲染当前窗口,不显示省略号。
如何区分受控与非受控分页?
传入 page(可选 pageSize)并配合 @update:page 处理函数,或直接使用 v-model:page。非受控用法依赖 defaultPage / defaultPageSize,让组件自行管理状态。
actionVariant 有什么用?
默认情况下 first/prev/next/last 操作按钮使用中性操作样式。开启 actionVariant 后,这些按钮也套用 variant 样式(即选中页码所用的样式,如实心主色外观),适用于当前页与操作按钮视觉融合的场景。
为什么第一页时 prev/first 被禁用?
page === 1 时 first/prev 自动禁用,page === pageCount 时 next/last 自动禁用,防止越界导航。设置 disabled: true 可禁用整个控件。
能完全自定义按钮吗?
可以 — first、prev、next、last、ellipsis、leading、trailing 插槽可替换默认内容;firstProps / prevProps / nextProps / lastProps 可将属性(包括样式)转发到对应区域。默认列表插槽通过 Aria list 接收感知 { page, pageCount } 的条目。
无障碍是如何处理的?
根元素是 nav 地标;每个按钮都有本地化的 aria-label(页码按钮使用 pageLabel 模板,如 “第 5 页”);当前页通过 aria-current="page" 播报;禁用按钮使用原生 disabled 属性,被辅助技术跳过。
能构建完全自定义的分页吗?
可以 — 从 @vean/aria/pagination 组合 PaginationRoot / PaginationList / PaginationListItem / PaginationEllipsis / PaginationFirst / PaginationPrev / PaginationNext / PaginationLast,并通过 providePaginationUi(或 SPagination 的 ui prop)注入样式。