在未使用框架內置分頁類時,手工拼裝分頁 HTML 是常見需求。本文梳理一個典型的 ThinkPHP 控制器分頁實現,涵蓋總數統計、頁碼計算、URL 組裝、首尾頁/上下頁/數字頁碼渲染,並說明優化方向。
public function alist() {
$this->validateLogin();
$this->createurl();
$article = M('article');
$page = I('get.page');
$perpage = 20;
// 當前頁修正
$page = (isset($page) && $page > 0) ? $page : 1;
$last = $page - 1;
$next = $page + 1;
// 分頁連結基礎 URL
$url = "https://" . $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'] . "?page=";
// 總記錄數(注意:select() 會撈全表,大數據量慎用)
$sum = count($article->where("is_delete=0")->select());
$pages = ceil($sum / $perpage);
$this->assign('sum', $sum);
$this->assign('pages', $pages);
// ---- 組裝分頁 HTML ----
$arr = '';
// 首頁 / 上一頁
if ($page > 1) {
$arr .= "<a href='{$url}1'>首頁</a>";
$arr .= "<a href='{$url}{$last}'>上一頁</a>";
} else {
$arr .= "<a href='javascript:void(0)' class='noallow'>首頁</a>";
$arr .= "<a href='javascript:void(0)' class='noallow'>上一頁</a>";
}
// 當前頁前兩個數字頁
if (($page - 2) > 0) {
$arr .= "<a href='{$url}" . ($page-2) . "' class='number'>" . ($page-2) . "</a>";
$arr .= "<a href='{$url}" . ($page-1) . "' class='number'>" . ($page-1) . "</a>";
} elseif (($page - 1) > 0) {
$arr .= "<a href='{$url}" . ($page-1) . "' class='number'>" . ($page-1) . "</a>";
}
// 當前頁高亮
$arr .= "<a href='{$url}{$page}' class='number current'>{$page}</a>";
// 當前頁後兩個數字頁
if (($page + 1) <= $pages) {
$arr .= "<a href='{$url}" . ($page+1) . "' class='number'>" . ($page+1) . "</a>";
if (($page + 2) <= $pages) {
$arr .= "<a href='{$url}" . ($page+2) . "' class='number'>" . ($page+2) . "</a>";
}
}
// 下一頁 / 尾頁
if ($page < $pages) {
$arr .= "<a href='{$url}{$next}'>下一頁</a>";
$arr .= "<a href='{$url}{$pages}'>尾頁</a>";
} else {
$arr .= "<a href='javascript:void(0)' class='noallow'>下一頁</a>";
$arr .= "<a href='javascript:void(0)' class='noallow'>尾頁</a>";
}
$this->assign('page', $arr);
// 實際分頁查詢
$data = $article->where("is_delete=0")->page($page, $perpage)->select();
$this->assign('article', $data);
$this->display();
}
| 步驟 | 說明 | 潛在問題 |
|---|---|---|
| 總數統計 | count(...->select()) 撈全表主鍵 | 大表會導致記憶體飆升,建議改用 count(*) |
| 頁碼計算 | ceil($sum/$perpage) | 邏輯正確 |
| URL 組裝 | 用 $_SERVER 動態生成 | 若有其他查詢參數會丟失,建議用 http_build_query 合併 |
| 頁碼渲染 | 顯示當前頁前後各 2 頁 | 邊界判斷較繁瑣,易漏 case |
| 分頁查詢 | ThinkPHP page($page,$perpage) 內部轉 LIMIT | 已自動處理偏移量 |
$article->where("is_delete=0")->count(),避免 select() 全表掃描。$url = U('alist', array_merge($_GET, ['page' => '__PAGE__'])); 利用框架 U 函數自動生成帶參鏈接。{current:3, total:10, pages:[1,2,3,4,5]},由 Vue/React 渲染,降低後端耦合。WHERE id > last_id LIMIT 20 游標分頁,避免 OFFSET 性能退化。手工分頁適合快速原型或特殊 UI 需求,但生產環境建議優先使用框架內置 \think\Page 或成熟分頁庫,兼顧性能、安全與維護性。