Material UI Pagination 分页组件详解:siblingCount、受控模式、usePagination Hook 与路由集成实战
【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Google's Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui
本文以 Material UI(MUI)官方文档 Pagination 组件页 为主体,覆盖从基础用法、页码范围裁剪(siblingCount/boundaryCount)、受控分页、路由集成到无头 HookusePagination的完整技术脉络,并结合 Pagination 组件源码 给出每个属性的默认值与底层实现依据,帮助你在博客、电商列表、后台表格等真实场景中正确选择Pagination或TablePagination,并写出可复制运行的分页代码。
组件定位与源码结构
Pagination组件让用户从一个页面范围中选择特定页码。它适用于「不使用无限加载」时对任意条目列表进行分页的场景,官方文档明确指出:在SEO 很重要的上下文(例如博客)中优先使用Pagination;而对大量表格数据分页,则应使用TablePagination组件。
组件的源码位于 packages/mui-material/src/Pagination 目录,核心文件包括:
- Pagination.js:组件主体,负责将
usePagination返回的条目映射为PaginationItem并管理焦点逻辑; - paginationClasses.ts:定义
MuiPagination的类名工具(root、ul、outlined、text); - 配套的无头 Hook
usePagination(位于 packages/mui-material/src/usePagination)与条目组件PaginationItem(位于packages/mui-material/src/PaginationItem),三者共同构成分页体系的完整分层。
基础用法
最简示例只需count(总页数)一个必填语义的属性,其余全部有默认值。基础示例见 BasicPagination:
import Pagination from '@mui/material/Pagination'; export default function BasicPagination() { return <Pagination count={10} />; }从 Pagination.js 源码 中解构出的默认值可以确认各属性缺省行为:
| 属性 | 默认值 | 说明 |
|---|---|---|
count | 1 | 总页数 |
page | — | 当前页(受控),从 1 开始 |
defaultPage | 1 | 非受控模式下的初始页码 |
variant | 'text' | 外观变体,可选outlined |
shape | 'circular' | 页码按钮形状,可选rounded |
size | 'medium' | 尺寸,可选small、large |
color | 'standard' | 选中页颜色,支持主题调色板颜色 |
siblingCount | 1 | 当前页前后各显示几页 |
boundaryCount | 1 | 首尾固定显示几页 |
showFirstButton/showLastButton | false | 是否显示「首页 / 末页」按钮 |
hidePrevButton/hideNextButton | false | 是否隐藏「上一页 / 下一页」按钮 |
renderItem | (item) => <PaginationItem {...item} /> | 自定义每个分页条目的渲染 |
外观变体:变体、形状与尺寸
文档提供了三组外观示例,分别对应variant、shape、size三个属性:
- Outlined pagination:
variant="outlined",示例见 PaginationOutlined; - Rounded pagination:
shape="rounded",示例见 PaginationRounded; - Pagination size:
size="small"或"large",示例见 PaginationSize。
在样式层面,Pagination.js 中根节点被styled('nav')定义,overridesResolver会按ownerState.variant叠加outlined/text对应的类名;内部<ul>固定为 flex 布局、flexWrap: 'wrap'、无列表样式,因此分页天然支持窄容器下的换行展示。
首页 / 末页按钮与隐藏前后翻页按钮
文档的 Buttons 章节说明:可以可选地启用首页、末页按钮,或禁用上一页、下一页按钮。示例见 PaginationButtons,对应属性为showFirstButton、showLastButton、hidePrevButton、hideNextButton,四个布尔属性均可自由组合。
一个容易踩的边界情况被源码显式处理了:当你在第 1 页点击「首页/上一页」、或在末页点击「下一页/末页」时,该按钮点击后会变为 disabled。如果此时焦点正停留在该按钮上,焦点会「丢失」,handleItemClick 与焦点恢复逻辑 会把焦点记录到pendingFocusRef,并在selectedPage更新后自动把焦点移到带aria-current="page"的选中页上。使用usePagination自行渲染时需要注意复刻这一行为。
自定义控制图标
文档说明控制图标(前后翻页箭头)可以自定义,示例见 CustomIcons,通过showFirstButton、showLastButton与自定义renderItem将PaginationItem的箭头替换为自定义 SVG/图标即可。
页码范围:siblingCount 与 boundaryCount
这是Pagination最核心的两个数字属性:
siblingCount:控制页码省略号两侧显示的数字个数(相对当前页);boundaryCount:控制首尾页号旁固定显示的页码个数。
官方示例 PaginationRanges 展示了四组组合(count={11}、defaultPage={6}):
<Stack spacing={2}> <Pagination count={11} defaultPage={6} siblingCount={0} /> <Pagination count={11} defaultPage={6} /> {/* Default ranges */} <Pagination count={11} defaultPage={6} siblingCount={0} boundaryCount={2} /> <Pagination count={11} defaultPage={6} boundaryCount={2} /> </Stack>结合默认值siblingCount=1、boundaryCount=1,默认渲染形如1 … 5 6 7 … 11;将siblingCount设为 0 则只剩当前页与边界页,将boundaryCount设为 2 则首尾各固定显示两页。这两个参数共同决定了条目数组中page、start-ellipsis、end-ellipsis三类条目的分布,其裁剪逻辑全部收敛在usePagination内部,组件层只负责渲染。
受控分页
非受控模式下用defaultPage指定初始页,onChange回调签名是onChange(event, page),其中page从 1 开始。受控模式则由外部状态接管,核心写法(对应 PaginationControlled 示例):
export default function PaginationControlled() { const [page, setPage] = React.useState(1); const handleChange = (event, value) => { setPage(value); }; return <Pagination page={page} count={10} onChange={handleChange} />; }传入page后组件进入受控模式,页码变化只会触发onChange,需要你在回调中更新状态;Pagination的pageprop 从 1 开始编号(源码 PropTypes 注释亦强调这一点,见 Pagination.js)。
路由集成:renderItem + 自定义组件
对于需要把页码写进 URL 的场景(SEO 友好),文档的 Router integration 章节给出了标准做法:通过renderItem把PaginationItem的component换成路由的Link。完整可运行的 PaginationLink 示例:
function Content() { const location = useLocation(); const query = new URLSearchParams(location.search); const page = parseInt(query.get('page') || '1', 10); return ( <Pagination page={page} count={10} renderItem={(item) => ( <PaginationItem component={Link} to={`/inbox${item.page === 1 ? '' : `?page=${item.page}`}`} {...item} /> )} /> ); }要点:renderItem接收的每个item都携带page、type、selected、onClick等字段,展开为PaginationItem的 props 即可;第 1 页的 URL 刻意不带查询参数,保证首页链接干净可分享。
无头 Hook:usePagination
文档明确:usePagination()是一个无头 Hook,面向高级定制场景暴露,它接受与Pagination组件几乎相同的选项,只是去掉了所有与 JSX 渲染相关的 prop;Pagination组件正是构建在这个 Hook 之上的。
import usePagination from '@mui/material/usePagination';Hook 的返回值为{ items, ... },items中每一项的type取值包含first、previous、page、next、last、start-ellipsis、end-ellipsis。UsePagination 官方示例 演示了完全自行渲染:遍历items,对start-ellipsis/end-ellipsis渲染省略号「…」,对page类型渲染原生<button>(选中时加粗),其余类型渲染翻页按钮,并手动实现「点击后按钮禁用时移动焦点到首/末页」的无障碍逻辑——这正是 Pagination.js 中 handleItemClick 所做的事情,说明 Hook 使用者需要自行保证焦点管理的等价行为。
TablePagination:与表格配套的另一种分页
文档特别提示:为大型表格数据分页应使用TablePagination组件,可参考文档 table 章节的 custom pagination options 内容。两者最关键的差异在页码起点:
Pagination的page从1开始,以匹配「页码要出现在 URL 中」的需求;TablePagination的page从0开始,以匹配渲染大量表格数据时零基 JavaScript 数组切片的需求(items.slice(page * rowsPerPage, ...))。
因此在混合使用两个组件时,务必做page的 ±1 换算,这是实际项目中最常见的 off-by-one 错误来源。
无障碍(Accessibility)
文档的 Accessibility 章节包含两部分,均已在源码中得到印证:
ARIA:根节点默认带有role="navigation"(源码中即渲染为<nav>)和aria-label="pagination navigation"(见 Pagination.js 第 158 行);每个分页条目都会获得说明其用途的aria-label,例如 "go to first page"、"go to previous page"、"go to page 1"。这些文案默认由 defaultGetAriaLabel 生成:type === 'page'时返回Go to page N(选中页则无前缀Go to),其他类型返回Go to ${type} page。可本地化的文案可通过getItemAriaLabelprop 覆盖,其签名为(type, page, selected) => string。
键盘:分页条目处于 Tab 顺序中,tabindex 为 "0",配合上文提到的焦点恢复逻辑,键盘用户在翻页后焦点会稳定落在新的选中页上。
样式类名与定制
paginationClasses.ts 导出了MuiPagination的全部类名:root(根元素)、ul(列表容器)、outlined(variant="outlined"时)、text(variant="text"时),可配合sx、classesprop 或主题components.MuiPagination.styleOverrides做样式覆盖。
小结
Material UI 的Pagination以「组件 + 无头 Hook」双层设计覆盖从开箱即用到完全自渲染的分页需求:variant/shape/size/color控制外观,siblingCount/boundaryCount控制页码范围,showFirstButton/showLastButton/hidePrevButton/hideNextButton控制导航按钮,renderItem打通路由集成,usePagination则把条目计算逻辑开放给定制场景;而表格数据分页请切换到TablePagination并注意两者页码起点(1 基 vs 0 基)的差异。所有属性默认值均可在 packages/mui-material/src/Pagination/Pagination.js 中逐一对应验证。
【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Google's Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考