页码总数必须用 Math.ceil(totalCount / pageSize),数据为空时需显式设为 1;HTML 应用语义化 nav+ol 结构,当前页用 aria-current="page";禁用 innerHTML 拼接;URL 参数须同步且正确编码。

页码总数怎么算才不会错
总页数必须用 Math.ceil(totalCount / pageSize),不能四舍五入、不能取整、更不能手写死。比如 99 条数据、每页 10 条,99 / 10 === 9.9,Math.floor(9.9) === 9 就会漏掉第 10 页;而 Math.round(9.9) === 10 看似碰巧对,但 101 条时就会错成 10 页(实际要 11 页)。
常见错误场景:
- 后端返回了
total字段,但前端误用data.length去算页数(比如接口只返当前页数据,没返总数) - 用户改了每页条数(如从 10 切到 20),但没重新算
totalPages,导致“下一页”按钮卡在旧值上 - 数据为空数组时
Math.ceil(0 / 10) === 0,此时应显式设为 1 页,否则页码栏直接消失
HTML结构必须带语义和可访问性标记
别用 <div class="pagination"> 包一堆 <a>。正确结构是:
<nav aria-label="页码导航">
<ol>
<li><a href="?page=1" rel="first">1</a></li>
<li><a href="?page=2">2</a></li>
<li aria-current="page"><span>3</span></li>
<li><a href="?page=4">4</a></li>
</ol>
</nav>
关键点:
立即学习“前端免费学习笔记(深入)”;
-
<nav>是必须的,让屏幕阅读器知道这是独立导航区 - 当前页用
aria-current="page"+<span>,不能是可点击的<a>,否则键盘用户会误触 - 上一页/下一页按钮若存在,应为
<button type="button">并带aria-disabled="true",而不是移除href后仅靠 CSS 灰色显示 - 省略号
…必须是真实文本节点(如<li><span>…</span></li>),不能用伪元素::before生成,否则读屏软件跳过
前端分页时 DOM 渲染别踩 innerHTML 大坑
用 innerHTML = htmlString 拼接页码,看似快,但有三个硬伤:
- 含用户输入内容时(比如搜索结果带 `<script>` 标签),直接插入会触发 XSS</script>
- 每次重绘都销毁全部子节点,已绑定的事件监听、焦点状态、自定义属性全丢
- 浏览器需重新解析 HTML 字符串,比原生 DOM 操作慢 2–3 倍(尤其页码多时)
推荐做法是:用 document.createElement + appendChild 动态构建,或用 DocumentFragment 批量插入。例如生成页码项:
function createPageItem(pageNum, isActive) {
const li = document.createElement('li');
if (isActive) {
li.setAttribute('aria-current', 'page');
li.innerHTML = `<span>${pageNum}</span>`;
} else {
const a = document.createElement('a');
a.href = `?page=${pageNum}`;
a.textContent = pageNum;
li.appendChild(a);
}
return li;
}
URL 参数同步不是可选项,而是必做项
用户点第 5 页后地址栏还是 ?page=1,刷新就回到首页——这不是体验差,是功能缺陷。
必须同步 URL 的两种典型方式:
- 服务端分页:每个
<a href>的链接本身就要带完整参数,比如/list?page=5&q=foo&sort=date,不能只写?page=5丢掉搜索条件 - 前端接管分页:点击时调用
history.pushState()+location.replace()更新地址栏,同时监听popstate事件响应浏览器前进/后退
最容易被忽略的是编码问题:如果搜索词含中文,href="?page=2&q=你好" 会因未编码导致请求 400 错误,正确做法是用 URLSearchParams 构造:
const params = new URLSearchParams(location.search);
params.set('page', '5');
window.history.pushState({}, '', `?${params}`);
真正麻烦的从来不是生成那几个数字按钮,而是让页码状态在 URL、内存变量、DOM 属性、无障碍属性之间始终保持一致——少同步一处,就有一个用户翻页后莫名其妙回到第一页。



















