总页数由count和list_rows自动计算得ceil(count / list_rows),list_rows必须为正整数,传0或负数会触发保底逻辑;total参数仅影响页数计算,需配合禁用自动count及全量数据才能生效。

ThinkPHP分页中 listRows 是怎么影响总页数的
总页数不是手动算出来的,而是由 ThinkPHP 分页类根据 count(总记录数)和 listRows(每页条数)自动推导:总页数 = ceil($count / $listRows)。只要 $count 和 $listRows 确定,总页数就唯一确定,没有中间变量可干预。
常见错误是以为改了 $page->lastPage() 或手动传入 totalPage 就能覆盖计算逻辑——实际无效,lastPage() 只是读取内部已算好的值。
-
listRows必须是正整数,传0或负数会导致除零或结果为1(底层用max(1, ceil(...))保底) - 如果数据库查不到数据(
$count === 0),无论listRows多大,总页数恒为1(这是 TP 的默认兜底行为) - 在使用
paginate()方法时,listRows是第二个参数:->paginate([15, ['list_rows' => 20]])中的20才生效,前面的15是当前页码,别搞混
如何让每页条数随用户选择动态变化而不崩分页链接
关键不是改分页逻辑,而是确保 URL 参数透传。ThinkPHP 默认只保留 page 参数,其他如 per_page=20 不会自动带入下一页链接,导致点“下一页”后又回到默认条数。
必须显式配置 var_page 和额外参数绑定:
$list = Db::name('user')->paginate([
'list_rows' => input('per_page/d', 15),
'query' => ['per_page' => input('per_page/d', 15)],
]);
这样生成的分页 HTML 链接里才会带 ?page=2&per_page=20。漏掉 query 配置,前端切换条数后翻页就失效。
- 不要用
$_GET['per_page']直接取值,要用input()并加类型过滤(/d),防止非数字注入导致list_rows变成0或负数 - 前端下拉选
10/20/50时,建议用location.href跳转并拼完整 URL,而不是只改page参数再提交表单——否则容易丢失筛选条件
count 查询被缓存导致总页数不更新的问题
ThinkPHP 对 paginate() 的 count 查询默认启用查询缓存(尤其在开启 data_cache_type 时),但业务中常有后台新增/删除数据后,前台分页仍显示旧的总页数,就是这个缓存没刷新。
解决方式不是关全局缓存,而是精准控制 count 查询不缓存:
$list = Db::name('article')
->where('status', 1)
->cache(false) // 关键:对主查询关缓存
->paginate(['list_rows' => 12]);
注意:cache(false) 必须加在 paginate() 调用前的链式调用中,且仅影响本次 count 查询;放在 paginate() 后面无效。
- 如果用了模型,可在模型的
baseQuery方法里统一加->cache(false),但要注意性能代价 - 某些场景(如高并发统计页)反而需要缓存 count,这时应单独用
Cache::get('article_count')+ 定时任务更新,而非依赖 paginate 自动 count
自定义分页总数时为什么 render() 仍显示错误页码范围
有人试图绕过自动 count,直接传入 total 参数:->paginate(['list_rows' => 10, 'total' => 127]),却发现页码栏还是显示 “1/12”,点第 12 页报 404 ——因为 total 只影响总页数计算,但分页器仍会按原始数据集切片,导致最后一页数据为空。
正确做法是:传 total 的同时,必须禁用自动 count,并确保数据查询本身也跳过 limit/offset(否则数据量对不上):
$data = Db::name('log')->where($map)->select(); // 全量查出(慎用!仅限小数据)
$list = collection($data)->paginate([
'list_rows' => 10,
'total' => 127,
'page' => input('page/d', 1),
]);
这种写法本质是内存分页,total 才真正生效。但数据量一大就会 OOM,所以只适合日志导出、后台配置页等低频小数据场景。
真实业务中,更稳妥的是用子查询预估总数,或接受「最后一页可能不满 listRows 条」的事实——那才是符合数据库分页本质的逻辑。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











