首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 分頁類 Paginator 完整實現(多種風格、URL 模式、AJAX 支援)

     編輯:PHP 相關知識

分頁核心參數

  • 總記錄數($total)
  • 每頁條數($perPage)
  • 當前頁碼($currentPage)
  • URL 模板($urlPattern,如 /list?page={page})
  • 顯示頁碼數($pageRange,兩側各幾個)

通用分頁類實現

<?php
/**
 * 通用分頁器
 * 支援:數字鏈接、首尾頁、上下頁、省略號、自定義模板、AJAX 模式
 */
class Paginator
{
    public function __construct(
        private int $total = 0,
        private int $perPage = 15,
        private int $currentPage = 1,
        private string $urlPattern = '?page={page}',
        private int $pageRange = 2,
        private array $options = []
    ) {
        $this->currentPage = max(1, min($this->currentPage, $this->lastPage()));
    }

    public function total(int $total): self
    {
        $this->total = $total;
        $this->currentPage = min($this->currentPage, $this->lastPage());
        return $this;
    }

    public function perPage(int $perPage): self
    {
        $this->perPage = max(1, $perPage);
        return $this;
    }

    public function currentPage(int $page): self
    {
        $this->currentPage = max(1, min($page, $this->lastPage()));
        return $this;
    }

    public function urlPattern(string $pattern): self
    {
        $this->urlPattern = $pattern;
        return $this;
    }

    public function lastPage(): int
    {
        return max(1, (int)ceil($this->total / $this->perPage));
    }

    public function offset(): int
    {
        return ($this->currentPage - 1) * $this->perPage;
    }

    public function limit(): int
    {
        return $this->perPage;
    }

    /** 獲取頁碼範圍 */
    public function getPageRange(): array
    {
        $last = $this->lastPage();
        if ($last <= 2 * $this->pageRange + 1) {
            return range(1, $last);
        }

        $start = max(1, $this->currentPage - $this->pageRange);
        $end   = min($last, $start + 2 * $this->pageRange);
        
        if ($end - $start < 2 * $this->pageRange) {
            $start = max(1, $end - 2 * $this->pageRange);
        }
        return range($start, $end);
    }

    /** 生成單個鏈接 */
    private function link(int $page, string $text, array $attrs = []): string
    {
        $url = str_replace('{page}', (string)$page, $this->urlPattern);
        $attrStr = '';
        foreach ($attrs as $k => $v) {
            $attrStr .= " $k=\"" . htmlspecialchars($v, ENT_QUOTES) . "\"";
        }
        if ($page === $this->currentPage) {
            return "$text";
        }
        return "$text";
    }

    /** 渲染 HTML(默認 Bootstrap 5 風格) */
    public function render(array $custom = []): string
    {
        $last = $this->lastPage();
        if ($last <= 1) return '';

        $html = '';
        return $html;
    }

    /** AJAX 模式:輸出 data-page 屬性,由前端 JS 接管 */
    public function renderAjax(string $containerSelector = '#list-container'): string
    {
        $last = $this->lastPage();
        if ($last <= 1) return '';

        $html = '
'; $range = $this->getPageRange(); foreach ([1, $this->currentPage - 1] as $p) { if ($p >= 1 && $p <= $last) { $html .= ''; } } foreach ($this->getPageRange() as $page) { $active = $page === $this->currentPage ? ' active' : ''; $html .= ''; } foreach ([$this->currentPage + 1, $last] as $p) { if ($p >= 1 && $p <= $last) { $html .= ''; } } $html .= '
'; return $html; } /** 獲取數據庫查詢 LIMIT 子句 */ public function getLimitClause(): string { return "LIMIT {$this->offset()}, {$this->perPage}"; } /** 靜態工廠方法 */ public static function make(int $total, int $perPage = 15): self { $page = (int)($_GET['page'] ?? 1); return new self($total, $perPage, $page); } }

使用示例

1. 基礎用法(MVC 控制器)

<?php
// 控制器
$total = $db->query("SELECT COUNT(*) FROM articles WHERE status=1")->fetchColumn();
$paginator = Paginator::make($total, 10);

$articles = $db->query("
    SELECT * FROM articles WHERE status=1 
    ORDER BY created_at DESC 
    {$paginator->getLimitClause()}
")->fetchAll();

// 視圖
echo $paginator->render();

2. 自定義 URL(路由模式)

$paginator = new Paginator($total, 10, $currentPage, '/articles/page/{page}');
// 生成:/articles/page/1, /articles/page/2 ...

3. AJAX 無刷新分頁

<!-- 列表容器 -->
<div id="article-list">...</div>

<!-- 分頁 -->
<?= $paginator->renderAjax('#article-list') ?>

<script>
document.querySelectorAll('.pagination-ajax .page-btn').forEach(btn => {
    btn.addEventListener('click', function() {
        const page = this.dataset.page;
        const container = document.querySelector(this.closest('.pagination-ajax').dataset.container);
        fetch(`?page=${page}&ajax=1`)
            .then(r => r.text())
            .then(html => container.innerHTML = html);
    });
});
</script>

4. API 分頁響應格式

<?php
// API 控制器
$paginator = Paginator::make($total, $perPage);
$data = $model->limit($paginator->perPage)->offset($paginator->offset())->get();

return response()->json([
    'data' => $data,
    'pagination' => [
        'total'        => $paginator->total,
        'per_page'     => $paginator->perPage,
        'current_page' => $paginator->currentPage,
        'last_page'    => $paginator->lastPage(),
        'from'         => $paginator->offset() + 1,
        'to'           => min($paginator->offset() + $paginator->perPage, $paginator->total),
    ],
    'links' => [
        'first' => $paginator->link(1, 'first'),
        'last'  => $paginator->link($paginator->lastPage(), 'last'),
        'prev'  => $paginator->currentPage > 1 ? $paginator->link($paginator->currentPage - 1, 'prev') : null,
        'next'  => $paginator->currentPage < $paginator->lastPage() ? $paginator->link($paginator->currentPage + 1, 'next') : null,
    ],
]);

常見分頁風格 CSS 類名對照

框架容器項目激活禁用鏈接
Bootstrap 5.pagination.page-item.active.disabled.page-link
Bootstrap 4.pagination.page-item.active.disabled.page-link
Tailwind.flex-bg-blue-600opacity-50px-3 py-1
Layui.layui-laypagea/span.layui-laypage-curr--

性能優化提示

  • 大數據量:避免 COUNT(*) 全表掃描,使用觸發器維護計數表、或 EXPLAIN 估算行數
  • 深分頁:LIMIT 100000, 20 極慢,改用 WHERE id > last_id ORDER BY id LIMIT 20(游標分頁)
  • 緩存總數:列表首頁緩存 total 60 秒,減少 COUNT 查詢
  • 靜態化:首頁、熱門分類首頁生成靜態 HTML 含分頁片段
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved