总页数必须用math.ceil(totalcount / pagesize)向上取整,数据为空时显式设为1;当前页需从url读取并校验范围;页码显示范围应围绕当前页居中动态计算,边界自动收缩;html须用包裹,页码用带href的或,当前页加aria-current="page"。

页码计算逻辑:总页数、当前页、显示范围怎么算
分页的核心不是渲染按钮,而是算出该显示哪些页码。常见错误是硬写 1 到 10,结果数据只有 3 页时还显示到 10,或者当前页在末尾时中间出现省略号断层。
关键三要素必须动态计算:
-
totalPages = Math.ceil(totalCount / pageSize)—— 总页数不能取整,必须向上取整 -
currentPage必须从 URL 参数或状态中读取,且需校验是否在1到totalPages范围内,越界就重置为1或totalPages - 显示页码数组(比如最多显示 5 个数字页)要围绕
currentPage居中展开,但边界要收缩:当currentPage ≤ 3时,从1开始;当currentPage ≥ totalPages - 2时,从totalPages - 4开始
HTML结构:语义化与可访问性不能只靠CSS
很多实现用一堆 <span></span> 或 <div> 堆按钮,导致屏幕阅读器无法识别这是导航,键盘用户也无法用 <code>Tab 正常遍历。
正确结构必须满足两点:
- 整个分页区域用
<nav aria-label="分页导航"></nav>包裹,让辅助技术明确上下文 - 每个页码按钮必须是
<a></a>(带href)或<button></button>(用于前端跳转),禁止用<span></span>+onclick;如果是纯前端路由,<a></a>的href应反映真实 URL(如?page=3),否则浏览器前进/后退失效 - 当前页必须用
aria-current="page"标记,例如:<a href="?page=5" aria-current="page">5</a>
省略号逻辑:什么时候该显示 ...,显示在哪
省略号不是装饰,是信息压缩的信号。它只应在「页码序列不连续」且「被跳过的页数 ≥ 2」时出现,否则会造成误导。
典型判断条件(以显示 5 个数字页为例):
- 左侧省略号:
startPage > 1且startPage !== 2→ 比如显示[1, ..., 4, 5, 6],不能是[1, ..., 2, 3, 4] - 右侧省略号:
endPage 且 <code>endPage !== totalPages - 1→ 比如[7, 8, 9, ..., 15],不能是[13, 14, 15, ..., 15] - 前后省略号不同时出现:如果
totalPages ≤ 7,通常不需要任何省略号;强行加反而干扰扫描
服务端分页 vs 前端分页:页码计算起点不同
页码计算本身没区别,但数据来源决定你能否信任 totalPages。这是最容易踩的坑。
- 服务端分页:每次请求带
page和limit,后端返回{ data: [...], pagination: { total: 123, page: 2, limit: 10 } }→totalPages可信,直接用 - 前端分页:所有数据已加载到 JS 中,
totalCount = dataArray.length→ 看似简单,但若数据后续会过滤(如搜索框输入),totalCount必须随过滤实时更新,否则页码错乱 - 混合场景(如无限滚动+页码跳转):不要复用同一套页码逻辑。跳转页码应触发完整重载,而不是仅移动视图位置
页码组件本身很薄,真正复杂的是它和数据流的耦合点——尤其是 totalCount 的来源是否稳定、是否延迟更新、是否被缓存。这些地方一松动,页码就“看起来对,点开错”。











