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

PHP 文章內容分頁深度解析:字數切割與分頁符兩大策略完整實作

     編輯:PHP 相關知識

長文顯示需分頁,核心策略有二:字數切割(程式自動)與分頁符(編輯手動)。本文深度剖析兩者優劣、HTML 標籤閉合難題、分頁類別架構與前端呈現模式。

策略對比:字數切割 vs 分頁符

維度字數切割分頁符 (如 <hr class="page">)
實作難度低(字串截取)中(需編輯器支援)
閱讀體驗差(可能斷句、斷標籤)優(人工控制斷點)
HTML 安全性極難保證標籤閉合天然避開標籤斷裂
維護成本零(自動)需編輯時插入標記
適用場景純文字、自動化匯入富文本、CMS 文章、技術文檔

分頁符策略完整實作

1. 資料庫存儲格式

-- 文章內容欄位存儲含分頁符的 HTML
<p>第一段內容...</p>
<hr class="page" />
<p>第二段內容...</p>
<hr class="page" />
<p>第三段內容...</p>

2. 核心分頁類別 Pager

<?php
class Pager {
    private int $totalPages;
    private int $currentPage;
    private int $subPages = 10;        // 顯示頁碼數量
    private string $linkTemplate;      // 分頁連結模板,含 {page} 佔位符
    private int $type = 2;             // 1=簡易模式, 2=經典模式

    public function __construct(int $totalPages, int $currentPage = 1, 
                                int $subPages = 10, string $link = '', int $type = 2) {
        $this->totalPages = max(1, $totalPages);
        $this->currentPage = max(1, min($currentPage, $this->totalPages));
        $this->subPages = $subPages;
        $this->type = $type;
        
        // 建立連結模板
        if ($link) {
            $this->linkTemplate = strpos($link, '?') === false ? $link . '?page={page}' 
                                                               : $link . '&page={page}';
        } else {
            $this->linkTemplate = $_SERVER['PHP_SELF'] . '?page={page}';
        }
    }

    public function render(): string {
        return $this->type === 1 ? $this->simpleMode() : $this->classicMode();
    }

    // 簡易模式:首頁 上頁 下頁 尾頁
    private function simpleMode(): string {
        $html = "第 {$this->currentPage} / {$this->totalPages} 頁 ";
        if ($this->currentPage > 1) {
            $html .= $this->link(1, '首頁') . ' ';
            $html .= $this->link($this->currentPage - 1, '上頁') . ' ';
        } else {
            $html .= '首頁 上頁 ';
        }
        if ($this->currentPage < $this->totalPages) {
            $html .= $this->link($this->currentPage + 1, '下頁') . ' ';
            $html .= $this->link($this->totalPages, '尾頁') . ' ';
        } else {
            $html .= '下頁 尾頁 ';
        }
        return $html;
    }

    // 經典模式:頁碼列表 + 首/尾/上/下
    private function classicMode(): string {
        $html = "第 {$this->currentPage} / {$this->totalPages} 頁 ";
        if ($this->currentPage > 1) {
            $html .= $this->link(1, '首頁') . ' ';
            $html .= $this->link($this->currentPage - 1, '上頁') . ' ';
        } else {
            $html .= '首頁 上頁 ';
        }

        // 計算顯示頁碼範圍
        $pages = $this->calculatePageRange();
        foreach ($pages as $p) {
            if ($p == $this->currentPage) {
                $html .= "[$p] ";
            } else {
                $html .= $this->link($p, "[$p]") . ' ';
            }
        }

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

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

    private function link(int $page, string $text): string {
        $url = str_replace('{page}', $page, $this->linkTemplate);
        return "$text";
    }
}
?>

3. 文章內容分頁邏輯

<?php
function getArticlePage(string $content, int $page = 1, string $delimiter = '<hr class="page" />'): array {
    $parts = explode($delimiter, $content);
    $total = count($parts);
    $page = max(1, min($page, $total));
    
    return [
        'content' => $parts[$page - 1] ?? '',
        'currentPage' => $page,
        'totalPages' => $total,
        'hasPrev' => $page > 1,
        'hasNext' => $page < $total,
    ];
}

// 控制器使用範例
$articleContent = $db->query("SELECT content FROM articles WHERE id=1")->fetchColumn();
$page = (int)($_GET['page'] ?? 1);
$paged = getArticlePage($articleContent, $page);

$pager = new Pager($paged['totalPages'], $page, 10, 'article.php?id=1');
?>
<article>
    <div class="content"><?= $paged['content'] ?></div>
    <nav class="pagination"><?= $pager->render() ?></nav>
</article>

字數切割策略:HTML 安全截取方案

若必須自動切割,請使用 DOMDocument 而非字串函式:

<?php
function truncateHtml(string $html, int $maxChars, string $suffix = '...'): string {
    $dom = new DOMDocument();
    $dom->loadHTML('<meta charset="UTF-8">' . $html, LIBHTML_HTML5 | LIBHTML_NOERROR);
    $body = $dom->getElementsByTagName('body')->item(0);
    
    $text = '';
    $iterator = new RecursiveIteratorIterator(new RecursiveDOMIterator($body));
    foreach ($iterator as $node) {
        if ($node->nodeType === XML_TEXT_NODE) {
            $text .= $node->textContent;
            if (mb_strlen($text) >= $maxChars) {
                // 截斷邏輯:移除後續節點
                $excess = mb_strlen($text) - $maxChars;
                $node->textContent = mb_substr($node->textContent, 0, -$excess) . $suffix;
                // 移除該節點之後的所有兄弟節點
                while ($next = $node->nextSibling) {
                    $next->parentNode->removeChild($next);
                }
                break 2; // 跳出雙層循環
            }
        }
    }
    return $dom->saveHTML($body);
}
?>

列表分頁 vs 內容分頁架構差異

類型資料來源分頁依據SQL 模式快取策略
列表分頁資料庫查詢結果集固定筆數LIMIT offset, size查詢結果快取、總數快取
內容分頁單一文章長文本分頁符/字數單次查詢完整內容分頁後 HTML 片段快取

採用分頁符策略搭配 Pager 類別,能同時滿足編輯靈活性、HTML 安全性、SEO 友善(單一 URL 含 rel=prev/next)三大需求,是成熟 CMS 系統的標準選擇。

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