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

PHP 分頁實戰大全:三種風格完整程式碼與使用指南

     編輯:PHP 綜合知識

方案一:簡易類別式(適合中小專案)

<?php
class SimplePaginator {
    private PDO $pdo;
    private string $baseSql;
    private int $perPage;
    private int $currentPage;
    private int $totalRows;
    private int $totalPages;

    public function __construct(PDO $pdo, string $baseSql, int $perPage = 15) {
        $this->pdo = $pdo;
        $this->baseSql = $baseSql;
        $this->perPage = $perPage;
        $this->currentPage = max(1, (int)($_GET['page'] ?? 1));
        $this->calculateTotals();
    }

    private function calculateTotals(): void {
        $countSql = "SELECT COUNT(*) FROM ({$this->baseSql}) AS t";
        $this->totalRows = (int)$this->pdo->query($countSql)->fetchColumn();
        $this->totalPages = (int)ceil($this->totalRows / $this->perPage);
        $this->currentPage = min($this->currentPage, max(1, $this->totalPages));
    }

    public function fetch(): array {
        $offset = ($this->currentPage - 1) * $this->perPage;
        $sql = "{$this->baseSql} LIMIT {$offset}, {$this->perPage}";
        return $this->pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    }

    public function render(string $cssClass = 'pagination'): string {
        if ($this->totalPages <= 1) return '';

        $html = "<nav><ul class=\"{$cssClass}\">";
        $range = $this->getPageRange(9);

        if ($this->currentPage > 1) {
            $html .= $this->link(1, '首頁');
            $html .= $this->link($this->currentPage - 1, '上一頁');
        }

        foreach ($range as $page) {
            $html .= $page === $this->currentPage
                ? "<li class=\"active\"><span>{$page}</span></li>"
                : $this->link($page, (string)$page);
        }

        if ($this->currentPage < $this->totalPages) {
            $html .= $this->link($this->currentPage + 1, '下一頁');
            $html .= $this->link($this->totalPages, '尾頁');
        }

        $html .= '</ul></nav>';
        return $html;
    }

    private function getPageRange(int $display): array {
        $half = (int)floor($display / 2);
        $start = max(1, $this->currentPage - $half);
        $end = min($this->totalPages, $start + $display - 1);
        $start = max(1, $end - $display + 1);
        return range($start, $end);
    }

    private function link(int $page, string $text): string {
        $url = $this->buildUrl($page);
        return "<li><a href=\"{$url}\">{$text}</a></li>";
    }

    private function buildUrl(int $page): string {
        $params = $_GET;
        $params['page'] = $page;
        return '?' . http_build_query($params);
    }

    public function getInfo(): array {
        return [
            'current' => $this->currentPage,
            'per_page' => $this->perPage,
            'total_pages' => $this->totalPages,
            'total_rows' => $this->totalRows,
        ];
    }
}

// 使用範例
$pdo = new PDO($dsn, $user, $pass);
$pager = new SimplePaginator($pdo, "SELECT * FROM articles WHERE status=1 ORDER BY id DESC", 10);
$articles = $pager->fetch();
echo $pager->render();

方案二:群組分頁類(適合大量頁碼、類似論壇翻頁)

<?php
class GroupPaginator {
    public int $perPage = 20;
    public int $groupSize = 10; // 每群顯示頁數
    public int $currentPage = 1;
    public int $currentGroup = 1;
    public int $totalRows = 0;
    public string $url = '';

    public function init(int $totalRows, string $url, int $page = 1, int $group = 1): void {
        $this->totalRows = $totalRows;
        $this->url = $url;
        $this->currentPage = max(1, $page);
        $this->currentGroup = max(1, $group);
    }

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

    public function getLimit(): string {
        $offset = ($this->currentPage - 1) * $this->perPage;
        return "LIMIT {$offset}, {$this->perPage}";
    }

    public function render(): string {
        $totalPages = $this->getTotalPages();
        $totalGroups = (int)ceil($totalPages / $this->groupSize);
        $this->currentGroup = min($this->currentGroup, $totalGroups);

        $startPage = ($this->currentGroup - 1) * $this->groupSize + 1;
        $endPage = min($startPage + $this->groupSize - 1, $totalPages);

        $html = '<div class="group-pager">';

        // 上一群
        if ($this->currentGroup > 1) {
            $prevGroup = $this->currentGroup - 1;
            $prevPage = ($prevGroup - 1) * $this->groupSize + 1;
            $html .= $this->link($prevPage, $prevGroup, '« 前群');
        }

        // 頁碼
        for ($p = $startPage; $p <= $endPage; $p++) {
            $html .= $p === $this->currentPage
                ? "<span class=\"current\">{$p}</span>"
                : $this->link($p, $this->currentGroup, (string)$p);
        }

        // 下一群
        if ($this->currentGroup < $totalGroups) {
            $nextGroup = $this->currentGroup + 1;
            $nextPage = ($nextGroup - 1) * $this->groupSize + 1;
            $html .= $this->link($nextPage, $nextGroup, '後群 »');
        }

        $html .= '</div>';
        return $html;
    }

    private function link(int $page, int $group, string $text): string {
        return "<a href=\"{$this->url}?page={$page}&group={$group}\">{$text}</a>";
    }
}

方案三:函數式輕量分頁(零依賴、複製即用)

<?php
/**
 * 輕量分頁函數
 * @param int $totalRows 總筆數
 * @param int $perPage 每頁筆數
 * @param string $baseUrl 基礎 URL(含 ? 及其他參數,不含 page)
 * @return array ['html' => 分頁 HTML, 'offset' => OFFSET, 'limit' => LIMIT 字串]
 */
function paginate(int $totalRows, int $perPage = 20, string $baseUrl = ''): array {
    $totalPages = max(1, (int)ceil($totalRows / $perPage));
    $currentPage = max(1, min((int)($_GET['page'] ?? 1), $totalPages));
    $offset = ($currentPage - 1) * $perPage;

    // 建構 URL
    $params = $_GET;
    unset($params['page']);
    $query = $params ? '?' . http_build_query($params) . '&' : '?';
    $url = $baseUrl ?: ($_SERVER['SCRIPT_NAME'] . $query);

    $html = '';
    if ($totalPages > 1) {
        $html = '<nav><ul class="pagination">';
        $display = 9;
        $half = (int)floor($display / 2);
        $start = max(1, $currentPage - $half);
        $end = min($totalPages, $start + $display - 1);
        $start = max(1, $end - $display + 1);

        if ($currentPage > 1) {
            $html .= '<li><a href="' . $url . 'page=1">首頁</a></li>';
            $html .= '<li><a href="' . $url . 'page=' . ($currentPage - 1) . '">上一頁</a></li>';
        }

        for ($i = $start; $i <= $end; $i++) {
            $html .= $i === $currentPage
                ? "<li class=\"active\"><span>{$i}</span></li>"
                : '<li><a href="' . $url . "page={$i}\">{$i}</a></li>";
        }

        if ($currentPage < $totalPages) {
            $html .= '<li><a href="' . $url . 'page=' . ($currentPage + 1) . '">下一頁</a></li>';
            $html .= '<li><a href="' . $url . "page={$totalPages}\">尾頁</a></li>";
        }
        $html .= '</ul></nav>';
    }

    return [
        'html' => $html,
        'offset' => $offset,
        'limit' => "LIMIT {$offset}, {$perPage}",
        'current_page' => $currentPage,
        'total_pages' => $totalPages,
        'total_rows' => $totalRows,
    ];
}

// 使用範例
$total = $pdo->query("SELECT COUNT(*) FROM logs")->fetchColumn();
$page = paginate($total, 50);
$stmt = $pdo->query("SELECT * FROM logs ORDER BY id DESC " . $page['limit']);
$logs = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo $page['html'];

三種方案比較選型

特性SimplePaginatorGroupPaginatorpaginate() 函數
程式碼量中中極少
物件導向是是否
適合頁數< 1000> 1000< 500
自訂樣式繼承覆寫 render()繼承覆寫 render()修改函數/傳入模板
API 模式支援getInfo() 回傳陣列需自行擴充回傳陣列含完整資訊
依賴PDO無無

進階:Ajax 無刷新分頁

<script>
// 通用 Ajax 分頁處理
document.querySelectorAll('.pagination a').forEach(a => {
    a.addEventListener('click', e => {
        e.preventDefault();
        const url = a.href;
        fetch(url, { headers: { 'X-Requested-With': 'XMLHttpRequest' } })
            .then(r => r.json())
            .then(data => {
                document.getElementById('list-container').innerHTML = data.html;
                document.getElementById('pager-container').innerHTML = data.pager;
                history.pushState(null, '', url);
            });
    });
});
</script>

<?php
// 後端判斷 Ajax 請求
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])) {
    echo json_encode([
        'html' => renderList($items),
        'pager' => $pager->render(),
    ]);
    exit;
}
// 否則正常輸出完整頁面
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved