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

PHP 靈活分頁類 SubPages:雙模式渲染與邏輯解耦實現

     編輯:PHP 相關知識

設計模式:策略模式在分頁渲染中的應用

SubPages 類展示了一種經典的策略模式雛形:將分頁數據計算 (核心邏輯) 與HTML 渲染策略 (展示邏輯) 分離。構造函數接收 $subPage_type 參數 (1=簡潔模式, 2=經典數字模式),內部調用不同的私有渲染方法 (subPageCss1, subPageCss2)。這種設計允許在不修改核心計算邏輯的前提下,輕鬆擴展新的顯示樣式 (如 Bootstrap 分頁、AJAX 無刷新分頁、API JSON 輸出)。

核心計算邏輯深度解析

1. 參數初始化與邊界保護


function __construct($each_disNums, $nums, $current_page, $sub_pages, $subPage_link, $subPage_type) {
    $this->each_disNums = intval($each_disNums); // 每頁條數
    $this->nums         = intval($nums);         // 總條數
    $this->current_page = $current_page ? intval($current_page) : 1; // 當前頁,默認 1
    $this->sub_pages    = intval($sub_pages);    // 頁碼組顯示數量 (如一次顯示 10 個頁碼)
    $this->pageNums     = ceil($this->nums / $this->each_disNums); // 總頁數
    $this->subPage_link = $subPage_link;         // 分頁鏈接前綴 (如 "list.php?page=")
    
    $this->show_SubPages($subPage_type); // 直接輸出 HTML (耦合輸出,見下文改進建議)
}

2. 智能頁碼組構造算法 construct_num_Page()

此算法解決「總頁數極大時,如何只顯示當前頁附近的固定數量頁碼」的問題。邏輯分三種情況:

  1. 總頁數 < 顯示數量:直接顯示所有頁碼 1 ... $pageNums。
  2. 當前頁靠近首頁 ($current_page <= 3):顯示 1, 2, ..., $sub_pages。
  3. 當前頁靠近尾頁 ($current_page > $pageNums - $sub_pages + 1):顯示最後 $sub_pages 頁 $pageNums-$sub_pages+1 ... $pageNums。
  4. 當前頁在中間:以當前頁為中心,前後擴展 (如當前頁 50,顯示 10 個頁碼,則顯示 46-55) $current_page-2 ... $current_page+7。

private function construct_num_Page() {
    if ($this->pageNums < $this->sub_pages) {
        // 情況 1
        for ($i=0; $i<$this->pageNums; $i++) $current_array[$i] = $i+1;
    } else {
        // 情況 2, 3, 4
        if ($this->current_page <= 3) {
            for ($i=0; $i<$this->sub_pages; $i++) $current_array[$i] = $i+1;
        } elseif ($this->current_page > $this->pageNums - $this->sub_pages + 1) {
            for ($i=0; $i<$this->sub_pages; $i++) $current_array[$i] = $this->pageNums - $this->sub_pages + 1 + $i;
        } else {
            for ($i=0; $i<$this->sub_pages; $i++) $current_array[$i] = $this->current_page - 2 + $i;
        }
    }
    return $current_array;
}

雙渲染模式實現

模式一:簡潔模式 (subPageCss1)

適合移動端或側邊欄空間受限場景,僅顯示「首頁、上一頁、下一頁、尾頁」四個操作鏈接,不顯示具體頁碼數字。


/* 輸出示例:
共 4523 條記錄,每頁顯示 10 條,當前第 1/453 頁 [首頁] [上一頁] [下一頁] [尾頁]
*/
private function subPageCss1() {
    $str = "共{$this->nums}條記錄,每頁顯示{$this->each_disNums}條,當前第{$this->current_page}/{$this->pageNums}頁 ";
    // 首頁/上一頁
    if ($this->current_page > 1) {
        $str .= "[首頁] ";
        $str .= "[上一頁] ";
    } else {
        $str .= "[首頁] [上一頁] ";
    }
    // 下一頁/尾頁
    if ($this->current_page < $this->pageNums) {
        $str .= "[下一頁] ";
        $str .= "[尾頁] ";
    } else {
        $str .= "[下一頁] [尾頁] ";
    }
    echo $str;
}

模式二:經典數字模式 (subPageCss2)

PC 端標準分頁體驗,包含頁碼數字組,當前頁高亮 (紅色加粗)。


/* 輸出示例:
當前第 1/453 頁 [首頁] [上一頁] 1 2 3 4 5 6 7 8 9 10 [下一頁] [尾頁]
*/
private function subPageCss2() {
    $str = "當前第{$this->current_page}/{$this->pageNums}頁 ";
    // 首頁/上一頁 (同模式一)
    // ...
    
    // 頁碼數字組
    $pages = $this->construct_num_Page();
    foreach ($pages as $p) {
        if ($p == $this->current_page) {
            $str .= "[{$p}]";
        } else {
            $str .= "[{$p}]";
        }
    }
    
    // 下一頁/尾頁 (同模式一)
    // ...
    echo $str;
}

架構缺陷與重構建議 (關鍵)

原類最大的問題在於構造函數中直接 echo 輸出 HTML,導致:

  • 難以測試:無法捕獲輸出進行斷言。
  • 難以複用:無法在 API 中返回 JSON 結構供前端 Vue/React 渲染。
  • 違反單一職責:計算與輸出耦合。
  • XSS 風險:$subPage_link 直接拼接輸出,未轉義。

重構方案:分離計算與渲染 (Data Transfer Object 模式)


class Pagination
{
    // ... 參數屬性、構造函數、construct_num_Page() 計算邏輯保持不變 ...

    // 核心改動:移除 echo,返回結構化數據
    public function getPaginationData(): array
    {
        $pages = $this->construct_num_Page();
        $pageLinks = [];
        foreach ($pages as $p) {
            $pageLinks[] = [
                'page'     => $p,
                'url'      => $this->subPage_link . $p,
                'is_current' => ($p == $this->current_page),
                'label'    => (string)$p,
            ];
        }

        return [
            'total_items'   => $this->nums,
            'per_page'      => $this->each_disNums,
            'current_page'  => $this->current_page,
            'last_page'     => $this->pageNums,
            'first_page_url' => $this->pageNums > 0 ? $this->subPage_link . '1' : null,
            'last_page_url'  => $this->pageNums > 0 ? $this->subPage_link . $this->pageNums : null,
            'prev_page_url'  => $this->current_page > 1 ? $this->subPage_link . ($this->current_page - 1) : null,
            'next_page_url'  => $this->current_page < $this->pageNums ? $this->subPage_link . ($this->current_page + 1) : null,
            'links'          => $pageLinks, // 頁碼組詳情
            'from'           => $this->nums > 0 ? (($this->current_page - 1) * $this->each_disNums) + 1 : null,
            'to'             => min($this->current_page * $this->each_disNums, $this->nums),
        ];
    }
}

// 控制器調用
$pagination = new Pagination($perPage, $total, $currentPage, 10, '?page=');
$data = $pagination->getPaginationData();

// 1. 模板渲染 (Smarty/Blade)
$tpl->assign('pagination', $data);

// 2. API 返回 JSON
return response()->json(['data' => $items, 'pagination' => $data]);

前端模板渲染示例 (Bootstrap 5 風格)



共 {$pagination.total_items} 條,第 {$pagination.current_page}/{$pagination.last_page} 頁

總結

SubPages 類通過 construct_num_Page() 實現了經典的滑動窗口頁碼算法,並以策略模式支持雙渲染模式,邏輯清晰實用。但其直接在構造函數中輸出 HTML 的設計嚴重限制了現代化應用 (API、前後端分離、單元測試)。重構核心在於將渲染邏輯外移,類僅負責計算並返回標準化數據結構 (DTO),由視圖層或 API 序列化層決定最終輸出格式。這才是符合現代 PHP 開發規範 (PSR, SOLID) 的分頁組件設計。

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