总页数需向上取整:const totalpages = math.floor((total + pagesize - 1) / pagesize);offset = (page - 1) * pagesize;末页判断用 currentpage >= totalpages,非取模;取模仅用于记录序号转页码。

分页时 page 和 pageSize 怎么算总页数?
总页数不是简单除法,必须向上取整。比如 103 条数据、每页 10 条,结果是 11 页,不是 103 / 10 = 10.3 向下取整的 10 页。
正确做法是:用取模判断是否有余数,有就加 1。
常见错误写法:Math.floor(total / pageSize) —— 这会漏掉最后一页;total / pageSize 直接转整数也一样错。
推荐写法(通用且无浮点误差):
const totalPages = Math.floor((total + pageSize - 1) / pageSize);或者更直观地用取模:
const totalPages = total % pageSize === 0 ? total / pageSize : Math.floor(total / pageSize) + 1;
offset 怎么从 page 和 pageSize 推导?
后端分页通常用 offset + limit,前端传的是 page=1 起始的页码。这里最容易错的是把第 1 页当成 offset=1,实际应为 0。
换算公式固定:offset = (page - 1) * pageSize
验证几个例子:
- 第 1 页 →
(1-1)*10 = 0 - 第 2 页 →
(2-1)*10 = 10 - 第 3 页 →
(3-1)*10 = 20
为什么不能直接用 % 判断当前页是否“最后一页”?
有人想用 currentPage % totalPages === 0 判最后一页,这是典型误用——% 是循环取余,不是边界检测。
真正要判断是否末页,只有一种安全方式:currentPage >= totalPages
而取模在这里的正经用途是:检查某条记录属于第几页。
例如,已知记录序号 index(从 0 开始),它在第几页?
const page = Math.floor(index / pageSize) + 1; // +1 是因为页码从 1 开始这个式子本质是整除,但等价于:
const page = (index - (index % pageSize)) / pageSize + 1;——
% 只是用来剥离余数,不是主逻辑。数据库 LIMIT/OFFSET 分页和取模有啥隐含风险?
当数据动态增删时,单纯靠 offset 分页会出现跳页或重复(尤其高并发场景)。这时候取模本身没毛病,但它的输入(total)可能已过期。
关键点:
-
total必须是查询前实时统计的,不能缓存太久 - 如果用游标分页(cursor-based),就完全绕开了
offset和取模,此时%无用武之地 - MySQL 的
LIMIT offset, size在大偏移量下性能陡降,offset越大,扫描行越多——这不是取模的问题,但常被一起误归因
取模只是算术工具,它不会自动帮你处理数据一致性或性能问题。真正容易被忽略的,是把“计算页码”和“安全获取数据”混为一谈。










