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

PHP 分頁功能完整實現:邏輯原理、AJAX 無刷新加載、前後端代碼實戰

     編輯:PHP 綜合知識

分頁是數據量大時的必備功能。本文提供從傳統 URL 分頁到現代 AJAX 無刷新加載的完整實現,涵蓋邏輯算法、資料庫查詢、前端渲染、用戶體驗優化。

分頁核心邏輯

<?php
// 輸入參數
$page = max(1, (int)($_GET['p'] ?? 1)); // 當前頁碼,最小 1
$pageSize = 10; // 每頁筆數

// 1. 獲取總筆數
$total = $pdo->query('SELECT COUNT(*) FROM articles')->fetchColumn();

// 2. 計算總頁數
$totalPages = ceil($total / $pageSize);
$page = min($page, max(1, $totalPages)); // 修正頁碼範圍

// 3. 計算偏移量
$offset = ($page - 1) * $pageSize;

// 4. 查詢當前頁數據
$stmt = $pdo->prepare('SELECT * FROM articles ORDER BY created_at DESC LIMIT ?, ?');
$stmt->bindValue(1, $offset, PDO::PARAM_INT);
$stmt->bindValue(2, $pageSize, PDO::PARAM_INT);
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>

傳統分頁導航 HTML 生成

<?php
function renderPagination(int $currentPage, int $totalPages, string $baseUrl = '?p='): string {
    if ($totalPages <= 1) return '';
    
    $html = '<nav aria-label="分頁"><ul class="pagination">';
    
    // 首頁/上一頁
    if ($currentPage > 1) {
        $html .= '<li><a href="' . $baseUrl . '1">首頁</a></li>';
        $html .= '<li><a href="' . $baseUrl . ($currentPage - 1) . '">上一頁</a></li>';
    }
    
    // 頁碼範圍計算 (顯示當前頁前後各 2 頁)
    $start = max(1, $currentPage - 2);
    $end = min($totalPages, $currentPage + 2);
    
    // 調整範圍保持 5 個頁碼
    if ($end - $start < 4) {
        if ($start == 1) $end = min(5, $totalPages);
        if ($end == $totalPages) $start = max(1, $totalPages - 4);
    }
    
    for ($i = $start; $i <= $end; $i++) {
        $class = $i === $currentPage ? ' class="active"' : '';
        $html .= "<li$class><a href=\"{$baseUrl}$i\">$i</a></li>";
    }
    
    // 下一頁/尾頁
    if ($currentPage < $totalPages) {
        $html .= '<li><a href="' . $baseUrl . ($currentPage + 1) . '">下一頁</a></li>';
        $html .= '<li><a href="' . $baseUrl . $totalPages . '">尾頁</a></li>';
    }
    
    $html .= '</ul></nav>';
    return $html;
}
?>

AJAX 無刷新分頁 (現代體驗)

後端 API:api/articles.php

<?php
header('Content-Type: application/json');
$page = max(1, (int)($_GET['page'] ?? 1));
$pageSize = 10;
// ... 查詢邏輯同上 ...
echo json_encode([
    'code' => 200,
    'data' => $items,
    'pagination' => [
        'current_page' => $page,
        'total_pages' => $totalPages,
        'total_items' => $total,
        'page_size' => $pageSize
    ]
]);
?>

前端 JS (原生 Fetch)

<script>
let currentPage = 1;
const container = document.getElementById('article-list');
const pagination = document.getElementById('pagination');

async function loadPage(page) {
    currentPage = page;
    const resp = await fetch(`api/articles.php?page=${page}`);
    const data = await resp.json();
    
    if (data.code === 200) {
        renderArticles(data.data);
        renderPagination(data.pagination);
    }
}

function renderArticles(items) {
    container.innerHTML = items.map(item => `
        <article>
            <h3>${escapeHtml(item.title)}</h3>
            <p>${escapeHtml(item.excerpt)}</p>
        </article>
    `).join('');
}

function renderPagination(pager) {
    let html = '';
    if (pager.current_page > 1) {
        html += `<button onclick="loadPage(${pager.current_page - 1})">上一頁</button>`;
    }
    for (let i = 1; i <= pager.total_pages; i++) {
        const active = i === pager.current_page ? ' class="active"' : '';
        html += `<button${active} onclick="loadPage(${i})">${i}</button>`;
    }
    if (pager.current_page < pager.total_pages) {
        html += `<button onclick="loadPage(${pager.current_page + 1})">下一頁</button>`;
    }
    pagination.innerHTML = html;
}

function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

// 初始載入
loadPage(1);
</script>

「載入更多」無限滾動模式

<script>
let loading = false;
let page = 1;
const observer = new IntersectionObserver(async (entries) => {
    if (entries[0].isIntersecting && !loading) {
        loading = true;
        page++;
        const resp = await fetch(`api/articles.php?page=${page}`);
        const data = await resp.json();
        if (data.code === 200 && data.data.length > 0) {
            data.data.forEach(item => {
                const el = document.createElement('article');
                el.innerHTML = `<h3>${escapeHtml(item.title)}</h3><p>${escapeHtml(item.excerpt)}</p>`;
                container.appendChild(el);
            });
        } else {
            observer.disconnect(); // 沒有更多
        }
        loading = false;
    }
});
observer.observe(document.getElementById('load-trigger'));
</script>
<div id="load-trigger" style="height: 1px;"></div>

效能優化關鍵

優化點方案
大偏移量查詢慢游標分頁 WHERE id > ? ORDER BY id LIMIT ? (需唯一遞增鍵)
COUNT(*) 慢快取總數、近似值、觸發器維護計數表
重複渲染前端虛擬列表、Vue/React 虛擬 DOM
SEO 支援SSR 渲染首屏、預渲染、動態渲染服務

分頁看似簡單,實則涉及資料庫優化、前端體驗、SEO 平衡等多維考量,根據業務場景選擇傳統分頁、AJAX 分頁或無限滾動。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved