thinkphp 8.0 模型分页需严格遵循查询构造器链式调用、显式传参控制url、启用simple模式优化count(*)性能、复制修改模板自定义渲染,并用$page$占位符实现跳转功能。

在 ThinkPHP 8.0 中实现模型数据分页时,既要保证分页逻辑正确、URL 参数不丢失,又要让前端样式贴合项目 UI,避免默认 Bootstrap 风格与 Element Plus 或 Tailwind 等现代框架冲突,同时还得避开大数据量下 COUNT(*) 导致的响应延迟问题。
基础分页调用:必须从查询构造器开始
先构建查询条件,最后一步才调用 paginate(),否则会报错或返回空分页对象。
✅ 正确写法:UserModel::where('status', 1)->order('id desc')->paginate(15);
❌ 错误写法:UserModel::where('status', 1)->select()->paginate(15)——【select() 后已执行 SQL,无法再分页】;
这一步不能跳过,ThinkPHP 的 paginate 只接受未执行的 Query 实例,不是 Collection 或数组。
传参控制:用数组参数替代数字参数
数字参数(如 ->paginate(10))自动读取 page 参数且不可定制,API 接口若用 page_no 字段就会失效。
方法一:显式指定当前页与每页条数
->paginate(['list_rows' => 10, 'page' => input('page_no', 1), 'var_page' => 'page_no']);
方法二:保留全部有效 GET 参数,避免翻页后搜索条件清空
->paginate(['query' => request()->except(['page', 'page_no'])]);
注意:别用 request()->only(['keyword', 'status']),字段不存在时会拼出 ?keyword=&status= 这种脏 URL。
性能优化:深分页与 simple 模式切换
当数据总量超百万、又没加联合索引时,COUNT(*) 查询会拖慢首屏加载。
第一步:启用 simple 模式,跳过总数统计
ThinkPHP 8.1.0 正式发布,深度优化路由与验证机制,完美兼容 PHP 8.4。本版本修复了数组路由配置异常,新增枚举值校验与高级数组验证功能,支持路由分类默认处理。作为高性能 PHP 框架的最新迭代,它延续了简洁实用的设计原则,提供更稳定的底层架构与更流畅的开发体验,助力开发者快速构建现代化 Web 应用与企业级系统。
->paginate(['list_rows' => 20, 'simple' => true]);
第二步:模板中改用 {$list->render()} → 它会自动适配 simple 分页结构,不显示“共 X 条”和末页按钮;
第三步:若需估算总数,可在控制器中缓存 $total = cache('user_total', function () { return UserModel::count(); }, 3600),再传给视图手动显示;
⚠️ simple 模式下 $list->lastPage() 不可用,只支持 $list->hasMore() 判断是否有下一页。
自定义分页模板:复制+修改+调用
ThinkPHP 不允许直接配置模板路径,必须复制默认模板到项目目录再引用。
方法1:找到框架内置模板位置(通常为 thinkphp/library/think/pagination/bootstrap.php),复制到 resources/view/paginate/custom.php;
方法2:在控制器中调用时显式指定:$list->render('custom');
模板内可用变量包括 $paginator、$currentPage、$hasPrevious、$hasNext,但不要用已废弃的 $render;
方法3:若想彻底替换 HTML 结构(比如把 <ul></ul> 改成 <div class="pager">),仅改模板不够,必须写自定义分页类并重写 <code>render() 和 getLinks() —— 否则页码范围仍按默认 ±2 生成。
添加跳转输入框:手动拼 HTML + JS
分页模板里不带跳转功能,得自己加。
在 custom.php 模板末尾插入:
<input type="number" min="1" max="<?=$paginator->lastPage()?>" value="<?=$paginator->currentPage()?>" style="width:60px;"><button onclick="location.href='<?=$paginator->url('$PAGE$')?>'.replace('$PAGE$', this.previousElementSibling.value)">跳转</button>;
关键点:【必须用 $PAGE$ 占位符,TP8 的 url() 方法只识别这个】;
别写成 [PAGE] 或 {page},否则链接生成失败。










