ThinkPHP6.x中paginate()必须作用于未执行的查询构造器对象,不可在select()等方法之后调用;正确写法为Db::table('user')->where()->paginate()或UserModel::where()->paginate(),且支持通过配置数组自定义页码参数名(如'var_page'=>'p')和透传参数。

ThinkPHP6.x中paginate()方法的正确调用方式
分页功能不是加个paginate()就自动好使的,它必须配合查询构造器(Db::table() 或模型查询)使用,且不能在select()之后再调用——那是无效的。
常见错误是写成:Db::table('user')->select()->paginate(10),这会直接报错或返回空对象,因为select()已执行SQL,paginate()需要的是未执行的查询对象。
- ✅ 正确写法:
Db::table('user')->where('status', 1)->paginate(10) - ✅ 模型写法:
UserModel::where('status', 1)->paginate(15)(每页15条) - ⚠️ 注意:
paginate()默认读取$_GET['page']参数,但实际URL中参数名可自定义,见下一条
自定义分页URL参数名和跳转链接生成逻辑
默认分页链接形如 ?page=2,但项目中常需改成 ?p=2 或嵌入路径(如 /admin/user/list?p=2),这时不能只改模板里的$page->render(),得从源头控制。
paginate()支持传入数组配置,其中query用于追加固定参数,var_page用于指定页码参数名:
立即学习“PHP免费学习笔记(深入)”;
UserModel::where('type', 'admin')
->paginate([
'list_rows' => 12,
'var_page' => 'p',
'query' => ['sort' => 'create_time']
]);
这样生成的链接就是 ?p=2&sort=create_time。若需完整路径(比如后台路由带模块),可在模板中用url()函数预设基础URL,再交由$page->render()补全页码参数。
前端模板里渲染分页HTML时的几个硬性限制
ThinkPHP6默认用Bootstrap风格渲染,但如果你没引入对应CSS,页面会显得错乱——这不是Bug,是样式依赖问题。
更关键的是:$page->render()返回的是HTML字符串,**必须原样输出**,不能被htmlspecialchars()或模板引擎自动转义(如{{ $page->render() }}在Blade中会转义标签)。ThinkPHP模板应写作:{:$page->render()}(冒号开头表示不转义)。
- ❌ 错误:
{{ $page->render() }}→ 显示为一堆 - 源码
- ✅ 正确:
{:$page->render()}或<?php echo $page->render(); ?> - ? 可选:用
simple()替代render()获取极简分页(上一页/下一页+总页数),适合API或轻量前端
手动传入当前页码时的兼容写法与性能隐患
有些场景(如AJAX分页、小程序)需要绕过$_GET,手动指定当前页。此时不能直接改$_GET['page'],而应传入page参数:
$page = input('get.p/d', 1); // 获取整型p参数,默认为1
$list = UserModel::paginate([
'list_rows' => 10,
'page' => $page
]);
但要注意:这种写法会跳过Page类内部对$_GET的自动识别逻辑,如果同时设置了var_page又手动传page,生成的链接可能仍用默认page参数,造成不一致。
真正安全的做法是统一入口:要么全靠$_GET自动解析(推荐),要么手动传page且**不设var_page**,再自行拼接跳转URL。
另外,paginate()默认会执行两次查询(一次算总数,一次取数据),大数据量下注意索引是否覆盖WHERE + ORDER BY字段,否则count慢会拖垮整个接口。



















