确认分页走模板渲染需检查:config('paginate.type')是否为'bootstrap'或'bootstrap4',再根据theme配置或render()参数确定实际加载路径,如view/paginate.html。

直接替换模板文件最简单,但必须确认当前 TP 版本走的是模板渲染路径,否则改了 paginate.html 也没用。
怎么确认分页是否在走模板渲染?
ThinkPHP 6.1+ 默认使用 Bootstrap4 驱动,它的 render() 方法内部会先尝试加载视图模板,找不到才回退到硬编码 HTML。所以你改模板前,得先看它到底找哪个路径:
- 默认查找
view/paginate.html(主题未设置时) - 若设置了
theme配置(如'theme' => 'admin'),则找view/admin/paginate.html - TP6.3+ 支持运行时指定:
$list->render(['template' => 'common/paginate']),此时只认你传的路径 - 如果
config('paginate.type')返回的是'bootstrap'或'bootstrap4',说明走的是驱动类逻辑,但依然会优先查模板
复制并修改默认模板文件(推荐新手)
不要去 vendor 里改 bootstrap4.php,一升级就丢。正确做法是把框架默认模板拷出来再改:
- 找到原始模板位置:
vendor/topthink/think-orm/src/paginator/driver/bootstrap4.php里的 HTML 字符串(或 TP6.3+ 的vendor/topthink/framework/src/view/paginate.html) - 在项目中新建
view/paginate.html,粘贴内容并按需删减,比如去掉aria-label、把<nav></nav>换成<div class="pager"> <li>确保控制器里调用的是 <code>$list->render(),而不是手动 echo$list->links()—— 后者绕过模板,直出驱动默认结构 -
config/paginate.php中写了'type' => 'Custom',但这个类没实现PaginatorRenderInterface,TP 就降级回用Bootstrap4驱动,而它又不读你的模板 —— 结果就是白改 - 用了
setTemplate()但路径写错,比如'template' => 'paginate'实际文件却是view/paginate.tpl,TP 找不到就静默 fallback - 模板里漏了
{$page->render()}或等效输出,只写了静态 HTML,分页链接自然不会生成 - URL 参数丢失:模板里写
@#@#@#@#@#@#@#@#@#@0是错的,url()不带查询参数,应改用<a href="%7B%24page->url(%24i,%20true)%7D"></a>或提前withQuery() - 新建类
app/common/Paginator/CustomDriver.php,实现think\contract\PaginatorRenderInterface - 在
render()里返回完整 HTML 字符串,例如:<div class="pager"> <button data-page="{$this->currentPage()-1}">上一页</button>...</div> - 在
config/paginate.php中配'driver' => 'custom'和'drivers' => ['custom' => \app\common\Paginator\CustomDriver::class] - 别在控制器里试图 new 一个 Paginator 再 setDriver —— driver 在实例化时就锁死了
为什么改了模板还是没生效?
常见卡点不在代码,而在配置和调用链:
想彻底控制 HTML 结构,必须重写 render() 方法
模板能改外观,但改不了语义结构(比如把页码从 <li> 改成 <span></span> 并加 data 属性)。这时只能自定义驱动:
最容易被忽略的一点:TP6 的分页对象在生成链接时,默认只保留 page 参数,其他 GET 变量(如搜索关键词、分类 ID)全丢了。不显式调用 withQuery(input('param.')) 或 appends(),翻页后搜索条件就清空了。











