本文目录导读:

这是一个用 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>
代码说明
关键点
- SQL 安全:使用 PDO 参数绑定,防止 SQL 注入。
- URL 参数保留:
buildUrl()自动保留除了page外的所有 GET 参数,如?category=1&page=2正常跳转。 - 边界处理:
- 当前页自动限制在
[1, totalPages]范围内。 - 总记录数为 0 或只有一页时不显示分页。
- 当前页自动限制在
- 灵活性:分页类可独立复用,只需传入三个参数。
文件结构
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 版本),可以告诉我,我会为你补充相应的实现。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播