ThinkPHP 內建 Page 類支援帶條件分頁,但常見問題是翻頁後查詢條件丟失。本文詳細講解如何正確傳遞 WHERE 條件、自定義分頁模板、實現無刷新分頁。
<?php
// 控制器方法
public function index() {
$map = []; // 條件數組
// 1. 從請求獲取查詢參數並構建條件
$keyword = input('get.keyword/s', '');
if ($keyword) {
$map['title|content'] = ['like', "%$keyword%"];
}
$status = input('get.status/d', 0);
if ($status) {
$map['status'] = $status;
}
// 2. 實例化分頁類(ThinkPHP 5/6 語法)
$list = Db::name('announcement')
->where($map)
->order('announcement_id DESC')
->paginate(15, false, [
'query' => request()->get(), // 關鍵:自動攜帶所有 GET 參數生成分頁鏈接
'var_page' => 'page',
]);
// 3. 模板賦值
$this->assign([
'list' => $list,
'keyword' => $keyword,
'status' => $status,
]);
return $this->fetch();
}
?>
關鍵點:paginate() 第三個參數 'query' => request()->get() 會將當前所有 GET 參數自動拼接到分頁鏈接中,翻頁時條件不丟失。
<!-- 模板文件 -->
<div class="pagination">
{$list->render()}
<!-- 或自定義模板 -->
{$list->appends(request()->get())->render('custom_pagination')}
</div>
自定義分頁模板(application/index/view/custom_pagination.html):
<nav aria-label="Page navigation">
<ul class="pagination">
<li class="page-item {if !$list->hasPages() || $list->currentPage() == 1}disabled{/if}">
<a class="page-link" href="{$list->url(1)}">首頁</a>
</li>
<li class="page-item {if !$list->hasPages() || !$list->hasPrevious()}disabled{/if}">
<a class="page-link" href="{$list->previousPageUrl()}">上一頁</a>
</li>
{for $i = max(1, $list->currentPage()-2); $i <= min($list->lastPage(), $list->currentPage()+2); $i++}
<li class="page-item {if $list->currentPage() == $i}active{/if}">
<a class="page-link" href="{$list->url($i)}">{$i}</a>
</li>
{/for}
<li class="page-item {if !$list->hasPages() || !$list->hasNext()}disabled{/if}">
<a class="page-link" href="{$list->nextPageUrl()}">下一頁</a>
</li>
<li class="page-item {if !$list->hasPages() || $list->currentPage() == $list->lastPage()}disabled{/if}">
<a class="page-link" href="{$list->url($list->lastPage())}">尾頁</a>
</li>
</ul>
</nav>
<?php
// 控制器中配置
$page = $list->appends(request()->get());
$page->setConfig('prev', '<img src="/static/img/prev.png" alt="上一頁">');
$page->setConfig('next', '<img src="/static/img/next.png" alt="下一頁">');
$page->setConfig('first', '');
$page->setConfig('last', '');
$page->setConfig('theme', '%UP_PAGE% %DOWN_PAGE%'); // 僅顯示上下頁
$this->assign('page', $page->render());
<!-- 列表容器 -->
<div id="list-container">
{include file="list_items" /}
</div>
<div id="pagination">
{$list->render()}
</div>
<script>
// 事件委託綁定分頁鏈接
$('#pagination').on('click', 'a', function(e) {
e.preventDefault();
const url = $(this).attr('href');
if (!url || $(this).parent().hasClass('disabled')) return;
$.get(url, function(html) {
// 假設後端返回完整頁面,提取列表與分頁部分
const $html = $($.parseHTML(html));
$('#list-container').html($html.find('#list-container').html());
$('#pagination').html($html.find('#pagination').html());
// 或後端直接返回 JSON {list: ..., pagination: ...}
});
});
</script>
後端判斷 AJAX 請求返回局部視圖:
<?php
if (request()->isAjax()) {
return [
'list' => $this->fetch('list_items'), // 局部模板
'pagination' => $list->render(),
];
}
return $this->fetch();
<?php
use think\Paginator;
$total = Db::name('announcement')->where($map)->count();
$page = new Paginator(
Db::name('announcement')->where($map)->order('id DESC')->limit(15)->select(),
15,
$total,
[
'query' => request()->get(),
'var_page' => 'page',
'path' => url('index'), // 手動指定路徑
]
);
| 問題 | 原因 | 解決 |
|---|---|---|
| 翻頁後條件丟失 | 未傳遞 query 參數 | paginate(15, false, ['query' => request()->get()]) |
| 分頁鏈接域名錯誤 | 反向代理/負載均衡導致 URL 構建異常 | 配置 app.request.domain 或手動 path => url('index') |
| 總數統計慢 | 大表 COUNT(*) 全表掃描 | 使用緩存總數、近似統計、或分表分庫 |
| AJAX 分頁重複綁定事件 | 每次渲染重新綁定 click | 使用事件委託 $(document).on('click', '#pagination a', ...) |
ThinkPHP 分頁核心在於 條件數組構建 + query 參數傳遞 + 模板渲染 三步。掌握 paginate() 的第三個參數配置、appends() 方法、自定義模板與 AJAX 局部刷新,即可應對 90% 分頁場景。