ThinkPHP 6 的 paginate() 传第二个参数 false 可启用 simple 模式,跳过 COUNT 查询,仅查当前页数据并支持 hasMorePages() 判断下一页,但不可调用 total() 或 lastPage()。

ThinkPHP 6 的 paginate() 如何跳过 COUNT 查询
直接用 simple 模式即可跳过总数统计,避免深分页时的性能雪崩。这不是“去掉总记录”的 hack,而是框架原生支持的轻量分页策略。
常见错误是以为改模板或删 HTML 就能隐藏总数——其实 COUNT 还在执行,只是前端不显示而已,数据库压力没变。
-
paginate(15, false):第二个参数传false即启用 simple 模式,只查当前页数据 + 判断是否有下一页($paginator->hasMorePages()) - 返回的
Paginator实例不再有total()、lastPage()等依赖总数的方法,调用会报错 - 模板里别再写
{$list->total()}或{$list->lastPage()},这些值不存在 - 如果你需要“共 X 条”,只能自己额外查一次
COUNT(*),但建议放弃——用户并不真正在意那个数字
自定义分页 HTML 输出必须替换模板文件
ThinkPHP 6 的 render() 方法默认硬编码了 Bootstrap 风格的 <ul class="pagination"></ul> 结构,不提供配置项开关。想改容器标签、加图标、换文字,光靠参数或 CSS 是做不到的。
关键动作是复制并重命名模板文件,然后显式调用它:
立即学习“PHP免费学习笔记(深入)”;
- 找到框架默认模板路径,通常是
thinkphp/library/think/pagination/bootstrap.php - 复制到你项目里,比如
resources/views/paginate/simple.blade.php(TP6 默认用 Blade)或resources/views/paginate/custom.php(普通 PHP 模板) - 控制器中调用:
$list->render('custom')—— 注意不带扩展名 - 模板内可用变量包括:
$paginator、$currentPage、$hasPrevious、$hasNext,但不要用已废弃的$render
appends() 保留搜索参数时容易漏掉空值
分页链接默认只保留当前 URL 路径,像 ?keyword=abc&status=1 这类参数不会自动带上。很多人用 appends(request()->only(['keyword', 'status'])),但一旦某个字段没传,就会生成 ?keyword=&status=1,既难看又可能触发后端空值逻辑。
- 更稳妥的是
appends(request()->except(['page'])),排除page同时保留所有非空参数 - 如果参数来自 POST 表单,需先在控制器里合并:
appends(array_merge($searchData, ['page' => $request->input('page', 1)])) - 中文参数会被自动
urlencode,但你自己拼 URL 时得手动urlencode(),否则可能乱码或 404
simple 模式下不能用 lastPage() 和 total()
这是最容易踩的坑:开了 simple 模式后还试图调用 $list->lastPage() 或在模板里写 {$list->total()},会直接抛出 BadMethodCallException。
因为 simple 模式根本不执行 COUNT(*),内部连总数字段都没存。你要的只是“上一页 / 下一页”和“有没有下一页”,那就老实用 $paginator->hasPrevious() 和 $paginator->hasNext()。
真要末页跳转?要么切回普通分页(接受性能代价),要么改用游标分页(基于 ID 或时间戳,无总数依赖)——后者才是百万级数据的正解。



















