页码数组必须动态生成,核心是围绕当前页动态伸缩显示范围,使用getPageNumbers函数控制可见页码段,结合边界修正与省略号逻辑;结构需语义化可访问,用包裹,当前页标记aria-current="page";URL须同步history.pushState或真实href;总页数严格用Math.ceil(totalCount / pageSize)计算。

页码数组必须动态生成,不能硬编码
硬写 [1, 2, 3, 4, 5, '...', totalPages] 看似省事,实际在总页数为 3 或 1000 时都会出错:要么漏页,要么卡顿、溢出屏幕。真实场景中,页码显示范围必须围绕 currentPage 动态伸缩。
关键逻辑是用函数控制可见页码段,例如:
function getPageNumbers(currentPage, totalPages, maxVisible = 5) {
if (totalPages <= maxVisible) return Array.from({ length: totalPages }, (_, i) => i + 1);
<p>const half = Math.floor(maxVisible / 2);
let start = Math.max(1, currentPage - half);
let end = Math.min(totalPages, currentPage + half);</p><p>if (start === 1) end = Math.min(totalPages, maxVisible);
if (end === totalPages) start = Math.max(1, totalPages - maxVisible + 1);</p><p>const pages = [];
if (start > 1) pages.push(1, '');
for (let i = start; i <= end; i++) pages.push(i);
if (end < totalPages) pages.push('', totalPages);</p><p>return pages;
}-
maxVisible指「最多显示几个数字页码」,不包含省略号和首尾 1/totalPages - 边界修正(
start === 1和end === totalPages分支)极易遗漏,会导致靠近头尾时显示断层 - 返回混合数组(数字 + 字符串
''),渲染时需判断类型:''渲染为禁用占位,数字渲染为可聚焦的<a></a>或<button></button>
HTML结构必须语义化且可访问
用 <div class="pagination"> 包一堆 <code><span></span> 是常见错误——屏幕阅读器无法识别导航上下文,键盘用户 Tab 键也无法顺序遍历。
正确结构必须满足三点:
立即学习“前端免费学习笔记(深入)”;
- 外层用
<nav aria-label="分页导航"></nav>,明确语义边界 - 页码项用
<ol></ol>(有序列表)或<ul></ul>,而非<div> 堆砌;当前页用 <code>aria-current="page"标记,且不能是可点击链接(避免误触) - 上一页/下一页按钮必须带
rel="prev"/rel="next",利于 SEO 和浏览器前进后退逻辑
示例片段:
<nav aria-label="分页导航">
<ol>
<li><a href="?page=1" rel="prev">上一页</a></li>
<li><a href="?page=1">1</a></li>
<li aria-current="page"><span>2</span></li>
<li><a href="?page=3">3</a></li>
<li><a href="?page=3" rel="next">下一页</a></li>
</ol>
</nav>URL 同步不能只靠 JS 状态
点击页码后仅更新组件内部 currentPage 状态,刷新页面就会回到第一页,也破坏分享链接和浏览器历史。
必须调用 history.pushState() 并同步 URL 查询参数:
- 前端路由场景:执行
history.pushState({ page: newPage }, '', `?page=${newPage}`) - 服务端渲染场景:每个页码
<a href="?page=3"></a>必须指向真实 URL,不能是#3或空href - 注意 URL 编码:若页码来自用户输入或非数字来源,需用
encodeURIComponent包裹 - 监听
popstate事件,在用户点浏览器前进/后退时恢复状态
总页数计算必须严格用 Math.ceil()
用 Math.floor(totalCount / pageSize) 或 Math.round() 都会出错。99 条数据、每页 10 条时,99 / 10 === 9.9,Math.floor(9.9) === 9 就直接丢掉第 10 页;Math.round(101 / 10) === 10 则少算一页。
- 正确公式:
totalPages = Math.ceil(totalCount / pageSize) - 数据为空时
Math.ceil(0 / 10) === 0,需显式设为1,否则页码栏消失 - 服务端分页时,
totalPages应以接口返回的pagination.total为准,而非前端用data.length自算 - 用户切换每页条数(如从 10 改为 20)后,必须重新计算
totalPages,否则“下一页”按钮逻辑失效
省略号不是装饰,是信息压缩信号;它只在跳过的页数 ≥ 2 时出现,且前后不同时存在——这点容易被忽略,但直接影响用户对页码连续性的判断。



















