Skip to content

17.3 分页功能

为什么需要分页

在 Web 应用程序中,当数据量较大时,分页是一种常见的技术,它可以:

  • 提高页面加载速度:只加载当前页的数据,减少数据传输量
  • 改善用户体验:避免一次性显示过多数据,使页面更整洁
  • 减轻服务器负担:减少数据库查询和数据处理的压力
  • 便于导航:用户可以方便地浏览不同页的数据

PHP 实现分页的方法

1. 基本分页原理

分页的基本原理是:

  1. 确定每页显示的记录数:通常为 10、20 或 50 条
  2. 计算总记录数:从数据库中查询总记录数
  3. 计算总页数:总记录数除以每页显示的记录数,向上取整
  4. 计算当前页的起始位置:(当前页码 - 1) * 每页显示的记录数
  5. 查询当前页的数据:使用 LIMIT 子句查询当前页的数据
  6. 生成分页导航:根据当前页码和总页数生成分页链接

2. 实现步骤

步骤 1:设置分页参数

php
// 设置分页参数
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1; // 当前页码
$per_page = 10; // 每页显示的记录数
$start = ($page - 1) * $per_page; // 起始位置

步骤 2:查询总记录数

php
// 查询总记录数
$sql = "SELECT COUNT(*) as total FROM users";
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_assoc($result);
$total = $row['total'];

// 计算总页数
$total_pages = ceil($total / $per_page);

步骤 3:查询当前页的数据

php
// 查询当前页的数据
$sql = "SELECT * FROM users ORDER BY id DESC LIMIT $start, $per_page";
$result = mysqli_query($conn, $sql);
$users = mysqli_fetch_all($result, MYSQLI_ASSOC);

步骤 4:生成分页导航

php
// 生成分页导航
$pagination = '';

if ($total_pages > 1) {
    // 上一页
    if ($page > 1) {
        $pagination .= '<a href="?page=' . ($page - 1) . '">上一页</a>';
    }
    
    // 页码链接
    for ($i = 1; $i <= $total_pages; $i++) {
        if ($i == $page) {
            $pagination .= '<span class="current">' . $i . '</span>';
        } else {
            $pagination .= '<a href="?page=' . $i . '">' . $i . '</a>';
        }
    }
    
    // 下一页
    if ($page < $total_pages) {
        $pagination .= '<a href="?page=' . ($page + 1) . '">下一页</a>';
    }
}

3. 使用第三方库实现分页

使用 Pagerfanta

Pagerfanta 是一个功能强大的分页库,支持多种 ORM 和模板引擎:

安装
bash
composer require pagerfanta/pagerfanta
使用
php
use Pagerfanta\Adapter\ArrayAdapter;
use Pagerfanta\Pagerfanta;

// 数据
$users = [/* 数据数组 */];

// 创建适配器
$adapter = new ArrayAdapter($users);

// 创建分页器
$pagerfanta = new Pagerfanta($adapter);
$pagerfanta->setMaxPerPage(10);
$pagerfanta->setCurrentPage($page);

// 获取当前页的数据
$currentPageResults = $pagerfanta->getCurrentPageResults();

// 生成分页导航
$paginationHtml = $pagerfanta->getNavigation();

使用 Laravel 的分页

如果使用 Laravel 框架,可以使用其内置的分页功能:

php
// 查询数据并分页
$users = DB::table('users')->paginate(10);

// 在视图中显示分页
{{ $users->links() }}

分页最佳实践

  1. 使用索引:为查询的字段添加索引,提高查询速度
  2. 使用 LIMIT 子句:只查询当前页的数据,减少数据传输量
  3. 缓存总记录数:如果数据不频繁变化,可以缓存总记录数,减少数据库查询
  4. 优化分页导航:只显示当前页附近的页码,避免显示过多页码
  5. 处理边界情况:处理第一页和最后一页的情况,避免出现无效的分页链接
  6. 支持 SEO:使用 rel="prev" 和 rel="next" 标签,帮助搜索引擎索引分页内容
  7. 提供每页显示条数选项:允许用户选择每页显示的记录数

实战演练

场景:用户列表分页

php
<?php
// 连接数据库
$conn = mysqli_connect('localhost', 'root', '', 'test');

// 设置分页参数
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$per_page = 10;
$start = ($page - 1) * $per_page;

// 查询总记录数
$sql = "SELECT COUNT(*) as total FROM users";
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_assoc($result);
$total = $row['total'];
$total_pages = ceil($total / $per_page);

// 查询当前页的数据
$sql = "SELECT * FROM users ORDER BY id DESC LIMIT $start, $per_page";
$result = mysqli_query($conn, $sql);
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户列表</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .pagination {
            display: flex;
            list-style: none;
            padding: 0;
        }
        .pagination li {
            margin: 0 5px;
        }
        .pagination a {
            display: block;
            padding: 5px 10px;
            border: 1px solid #ddd;
            text-decoration: none;
            color: #007bff;
        }
        .pagination a:hover {
            background-color: #f8f9fa;
        }
        .pagination .active a {
            background-color: #007bff;
            color: white;
            border-color: #007bff;
        }
    </style>
</head>
<body>
    <div class="container mt-5">
        <h1>用户列表</h1>
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>用户名</th>
                    <th>邮箱</th>
                    <th>创建时间</th>
                </tr>
            </thead>
            <tbody>
                <?php while ($user = mysqli_fetch_assoc($result)): ?>
                <tr>
                    <td><?php echo $user['id']; ?></td>
                    <td><?php echo $user['username']; ?></td>
                    <td><?php echo $user['email']; ?></td>
                    <td><?php echo $user['created_at']; ?></td>
                </tr>
                <?php endwhile; ?>
            </tbody>
        </table>
        
        <!-- 分页导航 -->
        <?php if ($total_pages > 1): ?>
        <ul class="pagination justify-content-center">
            <!-- 上一页 -->
            <?php if ($page > 1): ?>
            <li class="page-item">
                <a class="page-link" href="?page=<?php echo $page - 1; ?>">上一页</a>
            </li>
            <?php else: ?>
            <li class="page-item disabled">
                <a class="page-link" href="#">上一页</a>
            </li>
            <?php endif; ?>
            
            <!-- 页码 -->
            <?php for ($i = 1; $i <= $total_pages; $i++): ?>
            <li class="page-item <?php echo $i == $page ? 'active' : ''; ?>">
                <a class="page-link" href="?page=<?php echo $i; ?>"><?php echo $i; ?></a>
            </li>
            <?php endfor; ?>
            
            <!-- 下一页 -->
            <?php if ($page < $total_pages): ?>
            <li class="page-item">
                <a class="page-link" href="?page=<?php echo $page + 1; ?>">下一页</a>
            </li>
            <?php else: ?>
            <li class="page-item disabled">
                <a class="page-link" href="#">下一页</a>
            </li>
            <?php endif; ?>
        </ul>
        <?php endif; ?>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

场景:带搜索的分页

php
<?php
// 连接数据库
$conn = mysqli_connect('localhost', 'root', '', 'test');

// 获取搜索关键词
$keyword = isset($_GET['keyword']) ? $_GET['keyword'] : '';

// 设置分页参数
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$per_page = 10;
$start = ($page - 1) * $per_page;

// 构建查询条件
$where = '';
if ($keyword) {
    $where = " WHERE username LIKE '%$keyword%' OR email LIKE '%$keyword%'";
}

// 查询总记录数
$sql = "SELECT COUNT(*) as total FROM users" . $where;
$result = mysqli_query($conn, $sql);
$row = mysqli_fetch_assoc($result);
$total = $row['total'];
$total_pages = ceil($total / $per_page);

// 查询当前页的数据
$sql = "SELECT * FROM users" . $where . " ORDER BY id DESC LIMIT $start, $per_page";
$result = mysqli_query($conn, $sql);
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户列表</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container mt-5">
        <h1>用户列表</h1>
        
        <!-- 搜索表单 -->
        <form method="GET" class="mb-4">
            <div class="input-group">
                <input type="text" name="keyword" class="form-control" placeholder="搜索用户名或邮箱" value="<?php echo $keyword; ?>">
                <button type="submit" class="btn btn-primary">搜索</button>
            </div>
        </form>
        
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>用户名</th>
                    <th>邮箱</th>
                    <th>创建时间</th>
                </tr>
            </thead>
            <tbody>
                <?php while ($user = mysqli_fetch_assoc($result)): ?>
                <tr>
                    <td><?php echo $user['id']; ?></td>
                    <td><?php echo $user['username']; ?></td>
                    <td><?php echo $user['email']; ?></td>
                    <td><?php echo $user['created_at']; ?></td>
                </tr>
                <?php endwhile; ?>
            </tbody>
        </table>
        
        <!-- 分页导航 -->
        <?php if ($total_pages > 1): ?>
        <ul class="pagination justify-content-center">
            <!-- 上一页 -->
            <?php if ($page > 1): ?>
            <li class="page-item">
                <a class="page-link" href="?page=<?php echo $page - 1; ?>&keyword=<?php echo urlencode($keyword); ?>">上一页</a>
            </li>
            <?php else: ?>
            <li class="page-item disabled">
                <a class="page-link" href="#">上一页</a>
            </li>
            <?php endif; ?>
            
            <!-- 页码 -->
            <?php for ($i = 1; $i <= $total_pages; $i++): ?>
            <li class="page-item <?php echo $i == $page ? 'active' : ''; ?>">
                <a class="page-link" href="?page=<?php echo $i; ?>&keyword=<?php echo urlencode($keyword); ?>"><?php echo $i; ?></a>
            </li>
            <?php endfor; ?>
            
            <!-- 下一页 -->
            <?php if ($page < $total_pages): ?>
            <li class="page-item">
                <a class="page-link" href="?page=<?php echo $page + 1; ?>&keyword=<?php echo urlencode($keyword); ?>">下一页</a>
            </li>
            <?php else: ?>
            <li class="page-item disabled">
                <a class="page-link" href="#">下一页</a>
            </li>
            <?php endif; ?>
        </ul>
        <?php endif; ?>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

总结

分页是 Web 应用程序中的常见功能,它可以提高页面加载速度,改善用户体验,减轻服务器负担。PHP 提供了多种实现分页的方法,包括基本的 SQL 查询和使用第三方库。

在开发过程中,应该注意以下几点:

  • 合理设置每页显示的记录数
  • 优化数据库查询,使用索引和 LIMIT 子句
  • 生成分页导航,处理边界情况
  • 支持搜索和排序功能
  • 考虑 SEO 因素

通过合理实现分页功能,可以提高应用程序的性能和用户体验。

© 2026 编程马·菜鸟教程 版权所有