thinkphp分页必须用paginate()链式调用,不可先select()再分页;需透传query参数防搜索丢失;模板中用{$list->render()}输出分页,数据循环用{volist name="list"};总条数用{$list->total()}。

ThinkPHP 实现数据分页,核心就一条:用 paginate(),别手拼 limit 或先 select() 再分页——那会把全表数据拉进 PHP 内存,一翻页就卡死。
paginate() 必须链式调用,不能对数组分页
错误写法:Db::name('user')->select()->paginate(10),select() 已执行查询,返回的是 PHP 数组,paginate() 只是对数组切片,完全失去数据库层优化,总数不准、性能崩塌。
- 正确姿势:让
paginate()接管整个查询链,它会自动发两条 SQL——COUNT(*)算总数 + 带LIMIT的主查询 - 模型写法同理:
UserModel::where('status', 1)->order('id desc')->paginate(15) - 如果用了
join或子查询,确保关联字段索引到位,否则COUNT可能变慢
翻页后搜索条件丢失?查 query 配置
带关键词搜索的列表,点“下一页”回到第一页、keyword 消失——八成是没传 query 参数。框架默认只读 page,其他 GET 参数不会自动带上。
- 安全写法:
->paginate(10, false, ['query' => request()->param()]),透传全部参数 - 精准控制:
['query' => ['keyword' => $keyword, 'type' => $type]],避免传入敏感参数如token - 注意:如果用
input('get.'),需手动过滤键名,防止 URL 注入
分页 HTML 渲染和模板里怎么取数据
控制器 assign 后,模板里不是用 {$page},而是直接调用分页对象的 render() 方法;数据本身也是这个对象,不用额外解包。
- 数据循环:
{volist name="list" id="item"}{$item.name}{/volist}(list是你 assign 的变量名) - 分页输出:
{$list->render()},不是{$page},也不是{$list->show()} - 要拿总条数:
{$list->total()};当前页:{$list->currentPage()};总页数:{$list->lastPage()} - 样式定制不推荐改 CSS 覆盖,优先复制
vendor/topthink/framework/src/view/paginate.tpl到app/view/paginate.tpl并配置config/app.php中的'paginate' => ['template' => app_path() . 'view/paginate.tpl']
最易忽略的点:paginate() 默认从 $_GET['page'] 读当前页码,但如果你的接口走 POST 或 API,必须显式传 'page' => input('p/d', 1),否则永远是第一页。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











