你是否需要一个关于用PHP实现分页功能的完整项目案例

wen PHP项目 51

本文目录导读:

你是否需要一个关于用PHP实现分页功能的完整项目案例

  1. 环境准备
  2. 数据库结构
  3. PHP 分页核心类 Pagination.php
  4. 主文件 index.php(数据库连接 + 分页调用)
  5. 代码说明
  6. 运行效果
  7. 扩展建议

这是一个用 PHP 实现的分页功能完整案例,包含数据库结构、核心代码、前端展示及注释说明。


环境准备

  • PHP 7.0+
  • MySQL 5.6+
  • Web 服务器:Apache/Nginx

数据库结构

创建一张测试表 articles

CREATE DATABASE IF NOT EXISTS `demo` DEFAULT CHARSET utf8mb4;
USE `demo`;
CREATE TABLE `articles` (
  `id` int(11) NOT NULL AUTO_INCREMENT, varchar(200) NOT NULL,
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入50条测试数据
INSERT INTO `articles` (`title`, `created_at`) VALUES1', '2024-01-01 10:00:00'),2', '2024-01-02 10:00:00'),
...  -- 实际可写脚本批量插入,此处省略50', '2024-02-19 10:00:00');

PHP 分页核心类 Pagination.php

<?php
/**
 * 分页类 - 支持样式自定义和URL参数处理
 */
class Pagination {
    private $total;          // 总记录数
    private $pageSize;       // 每页显示条数
    private $currentPage;    // 当前页码
    private $totalPages;     // 总页数
    private $url;            // 基础URL(不含page参数)
    /**
     * @param int $total      总记录数
     * @param int $pageSize   每页显示条数
     * @param int $currentPage 当前页码
     */
    public function __construct($total, $pageSize = 10, $currentPage = 1) {
        $this->total = max(0, intval($total));
        $this->pageSize = max(1, intval($pageSize));
        $this->currentPage = max(1, intval($currentPage));
        $this->totalPages = ceil($this->total / $this->pageSize);
        // 当前页不能超过总页数
        if ($this->currentPage > $this->totalPages && $this->totalPages > 0) {
            $this->currentPage = $this->totalPages;
        }
        // 生成基础URL(剔除原有的page参数)
        $this->buildUrl();
    }
    /**
     * 构造基础URL,保留其他GET参数
     */
    private function buildUrl() {
        $params = $_GET;
        unset($params['page']); // 移除page参数
        $query = http_build_query($params);
        $this->url = $_SERVER['PHP_SELF'] . ($query ? '?' . $query . '&page=' : '?page=');
    }
    /**
     * 获取SQL中的LIMIT起始位置
     * @return int
     */
    public function getOffset() {
        return ($this->currentPage - 1) * $this->pageSize;
    }
    /**
     * 获取每页条数
     * @return int
     */
    public function getPageSize() {
        return $this->pageSize;
    }
    /**
     * 生成HTML分页导航(Bootstrap风格,可替换class)
     * @return string
     */
    public function render() {
        if ($this->totalPages <= 1) {
            return ''; // 只有一页不显示分页
        }
        $html = '<nav aria-label="Page navigation"><ul class="pagination">';
        // 上一页
        if ($this->currentPage == 1) {
            $html .= '<li class="page-item disabled"><span class="page-link">上一页</span></li>';
        } else {
            $html .= '<li class="page-item"><a class="page-link" href="' . $this->url . ($this->currentPage - 1) . '">上一页</a></li>';
        }
        // 页码按钮 - 显示前后各2页,当前页高亮
        $range = 2; // 显示前后页数
        $start = max(1, $this->currentPage - $range);
        $end = min($this->totalPages, $this->currentPage + $range);
        // 第一页
        if ($start > 1) {
            $html .= '<li class="page-item"><a class="page-link" href="' . $this->url . '1">1</a></li>';
            if ($start > 2) {
                $html .= '<li class="page-item disabled"><span class="page-link">...</span></li>';
            }
        }
        for ($i = $start; $i <= $end; $i++) {
            if ($i == $this->currentPage) {
                $html .= '<li class="page-item active"><span class="page-link">' . $i . '</span></li>';
            } else {
                $html .= '<li class="page-item"><a class="page-link" href="' . $this->url . $i . '">' . $i . '</a></li>';
            }
        }
        // 最后一页
        if ($end < $this->totalPages) {
            if ($end < $this->totalPages - 1) {
                $html .= '<li class="page-item disabled"><span class="page-link">...</span></li>';
            }
            $html .= '<li class="page-item"><a class="page-link" href="' . $this->url . $this->totalPages . '">' . $this->totalPages . '</a></li>';
        }
        // 下一页
        if ($this->currentPage == $this->totalPages) {
            $html .= '<li class="page-item disabled"><span class="page-link">下一页</span></li>';
        } else {
            $html .= '<li class="page-item"><a class="page-link" href="' . $this->url . ($this->currentPage + 1) . '">下一页</a></li>';
        }
        $html .= '</ul></nav>';
        return $html;
    }
    /**
     * 获取当前页码
     * @return int
     */
    public function getCurrentPage() {
        return $this->currentPage;
    }
    /**
     * 获取总页数
     * @return int
     */
    public function getTotalPages() {
        return $this->totalPages;
    }
}

主文件 index.php(数据库连接 + 分页调用)

<?php
require_once 'Pagination.php';
// 数据库配置
$host = 'localhost';
$dbname = 'demo';
$username = 'root';
$password = '123456';
try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die('数据库连接失败: ' . $e->getMessage());
}
// 分页参数
$pageSize = 10; // 每页10条
$currentPage = isset($_GET['page']) ? intval($_GET['page']) : 1;
if ($currentPage < 1) $currentPage = 1;
// 1. 获取总记录数
$stmt = $pdo->query("SELECT COUNT(*) FROM articles");
$total = $stmt->fetchColumn();
// 2. 初始化分页类
$pagination = new Pagination($total, $pageSize, $currentPage);
// 3. 获取当前页数据
$offset = $pagination->getOffset();
$stmt = $pdo->prepare("SELECT * FROM articles ORDER BY created_at DESC LIMIT :limit OFFSET :offset");
$stmt->bindValue(':limit', $pageSize, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$articles = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">PHP分页案例</title>
    <!-- 引入Bootstrap样式(仅用于UI,非必须) -->
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-4">
    <h2 class="mb-4">文章列表(共<?php echo $total; ?>条,每页<?php echo $pageSize; ?>条)</h2>
    <table class="table table-bordered table-hover">
        <thead class="thead-light">
            <tr>
                <th>ID</th>
                <th>标题</th>
                <th>创建时间</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($articles as $article): ?>
            <tr>
                <td><?php echo $article['id']; ?></td>
                <td><?php echo htmlspecialchars($article['title']); ?></td>
                <td><?php echo $article['created_at']; ?></td>
            </tr>
            <?php endforeach; ?>
            <?php if (count($articles) == 0): ?>
            <tr><td colspan="3" class="text-center">暂无数据</td></tr>
            <?php endif; ?>
        </tbody>
    </table>
    <!-- 分页导航 -->
    <div class="d-flex justify-content-center">
        <?php echo $pagination->render(); ?>
    </div>
    <!-- 显示当前页码信息 -->
    <p class="text-center text-muted">
        第 <?php echo $pagination->getCurrentPage(); ?> / <?php echo $pagination->getTotalPages(); ?> 页
    </p>
</div>
</body>
</html>

代码说明

关键点

  1. SQL 安全:使用 PDO 参数绑定,防止 SQL 注入。
  2. URL 参数保留buildUrl() 自动保留除了 page 外的所有 GET 参数,如 ?category=1&page=2 正常跳转。
  3. 边界处理
    • 当前页自动限制在 [1, totalPages] 范围内。
    • 总记录数为 0 或只有一页时不显示分页。
  4. 灵活性:分页类可独立复用,只需传入三个参数。

文件结构

project/
│  index.php          # 主页面
│  Pagination.php     # 分页类
└─ (可添加 config.php 统一管理数据库配置)

运行效果

  • 访问 http://localhost/project/index.php 即可看到分页列表。
  • 点击页码或上下页正常跳转,地址栏 ?page=N 自动变化。

扩展建议

  • 样式定制:修改 render() 中的 HTML 结构即可适配任意 CSS 框架。
  • AJAX 分页:在前端用 JS 捕获点击事件,通过 fetch 异步请求 ?page=X&ajax=1 实现无刷新分页。
  • 大数据量优化:当数据量极大时,COUNT(*) 可能较慢,可改用 EXPLAIN 估算或缓存总数。

如果你需要更具体的功能(如搜索分页、排序分页、AJAX 版本),可以告诉我,我会为你补充相应的实现。

抱歉,评论功能暂时关闭!