Hyperf分页器:数据分页与分页样式定制
还在为海量数据的分页展示而烦恼?Hyperf分页器组件为您提供一站式解决方案,从基础分页到高级定制,让数据展示变得优雅而高效!
📋 读完本文您将获得
- Hyperf分页器的核心概念与工作原理
- 多种分页方式的实战代码示例
- 分页样式深度定制技巧
- 性能优化与最佳实践
- 常见问题排查与解决方案
🚀 Hyperf分页器组件概述
Hyperf分页器是一个独立且强大的组件,专门用于处理数据分页需求。它提供了两种主要的分页器类型:
| 分页器类型 | 特点 | 适用场景 |
|---|---|---|
Paginator | 简单分页,不计算总数 | 大数据量、性能敏感场景 |
LengthAwarePaginator | 完整分页,包含总数统计 | 需要显示总页数的场景 |
核心架构设计
🔧 安装与基础配置
安装分页器组件
composer require hyperf/paginator
基础使用示例
<?php
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Paginator\Paginator;
use Hyperf\Collection\Collection;
#[AutoController]
class UserController
{
public function index(RequestInterface $request)
{
$currentPage = (int) $request->input('page', 1);
$perPage = (int) $request->input('per_page', 15);
// 模拟数据集合
$data = [
['id' => 1, 'name' => '张三', 'email' => 'zhangsan@example.com'],
['id' => 2, 'name' => '李四', 'email' => 'lisi@example.com'],
// ... 更多数据
];
$collection = new Collection($data);
$pageData = array_values($collection->forPage($currentPage, $perPage)->toArray());
return new Paginator($pageData, $perPage, $currentPage, [
'path' => $request->getUri()->getPath()
]);
}
}
📊 数据库分页实战
查询构造器分页
<?php
use Hyperf\DbConnection\Db;
class ProductController
{
public function list()
{
$perPage = 20;
// 基础分页查询
$products = Db::table('products')
->where('status', 1)
->orderBy('created_at', 'desc')
->paginate($perPage);
// 复杂条件分页
$filteredProducts = Db::table('products')
->where('category_id', 1)
->where('price', '>', 100)
->where(function ($query) {
$query->where('stock', '>', 0)
->orWhere('is_preorder', 1);
})
->paginate($perPage, ['*'], 'page', 2); // 指定页码
return $products;
}
}
模型分页
<?php
namespace App\Model;
use Hyperf\DbConnection\Model\Model;
class User extends Model
{
protected $table = 'users';
}
class UserController
{
public function index()
{
// 简单模型分页
$users = User::paginate(15);
// 带条件的分页
$activeUsers = User::where('status', 'active')
->orderBy('last_login', 'desc')
->paginate(10);
// 关联关系分页
$usersWithPosts = User::with(['posts' => function ($query) {
$query->where('published', true);
}])->paginate(20);
return $activeUsers;
}
}
🎨 分页样式深度定制
自定义分页响应格式
<?php
namespace App\Service;
use Hyperf\Paginator\AbstractPaginator;
use Hyperf\Contract\Arrayable;
class CustomPaginator implements Arrayable
{
protected AbstractPaginator $paginator;
public function __construct(AbstractPaginator $paginator)
{
$this->paginator = $paginator;
}
public function toArray(): array
{
return [
'meta' => [
'current_page' => $this->paginator->currentPage(),
'per_page' => $this->paginator->perPage(),
'total' => method_exists($this->paginator, 'total') ? $this->paginator->total() : null,
'last_page' => method_exists($this->paginator, 'lastPage') ? $this->paginator->lastPage() : null,
'from' => $this->paginator->firstItem(),
'to' => $this->paginator->lastItem(),
],
'links' => [
'first' => $this->paginator->url(1),
'last' => method_exists($this->paginator, 'lastPage') ? $this->paginator->url($this->paginator->lastPage()) : null,
'prev' => $this->paginator->previousPageUrl(),
'next' => $this->paginator->nextPageUrl(),
],
'data' => $this->paginator->items(),
];
}
}
// 使用示例
$paginator = User::paginate(15);
$customResponse = new CustomPaginator($paginator);
return response()->json($customResponse->toArray());
分页URL定制
<?php
class ArticleController
{
public function list(RequestInterface $request)
{
$articles = Article::paginate(10);
// 自定义路径和参数
$articles->withPath('/articles/list')
->appends(['sort' => 'date', 'order' => 'desc']);
// 添加片段标识
$articles->fragment('article-list');
return $articles;
}
}
分页链接数量控制
<?php
// 控制分页链接显示数量
$paginator = User::paginate(15);
$paginator->onEachSide(2); // 当前页左右各显示2个页码链接
// 生成自定义页码范围
$pageUrls = $paginator->getUrlRange(
max(1, $paginator->currentPage() - 3),
min($paginator->lastPage(), $paginator->currentPage() + 3)
);
⚡ 性能优化策略
大数据量分页优化
<?php
class BigDataController
{
public function largeDataset()
{
// 使用简单分页避免COUNT查询
$data = DB::table('large_table')
->orderBy('id')
->simplePaginate(100); // 使用simplePaginate避免总数计算
// 使用游标分页(Cursor Pagination)
$cursor = request()->input('cursor');
$data = DB::table('large_table')
->orderBy('id')
->when($cursor, function ($query, $cursor) {
return $query->where('id', '>', $cursor);
})
->limit(100)
->get();
return [
'data' => $data,
'next_cursor' => $data->last()?->id
];
}
}
分页缓存策略
<?php
use Hyperf\Cache\Annotation\Cacheable;
class CachedController
{
#[Cacheable(prefix: "users_page", ttl: 300)]
public function cachedUsers($page = 1)
{
return User::paginate(15, ['*'], 'page', $page);
}
// 手动缓存分页结果
public function manualCache()
{
$cacheKey = 'users_page_' . request()->input('page', 1);
return cache()->remember($cacheKey, 300, function () {
return User::with(['profile', 'roles'])
->orderBy('created_at', 'desc')
->paginate(15);
});
}
}
🔍 高级功能探索
自定义分页解析器
<?php
use Hyperf\Paginator\Paginator;
// 设置自定义当前页解析器
Paginator::currentPageResolver(function ($pageName = 'page') {
return request()->input($pageName, 1);
});
// 设置自定义路径解析器
Paginator::currentPathResolver(function () {
return request()->getUri()->getPath();
});
// 设置查询字符串解析器
Paginator::queryStringResolver(function () {
return request()->getQueryParams();
});
分页器宏扩展
<?php
use Hyperf\Paginator\Paginator;
use Hyperf\Collection\Collection;
// 添加自定义方法到分页器
Paginator::macro('toCustomFormat', function () {
return [
'list' => $this->items(),
'pagination' => [
'current' => $this->currentPage(),
'pageSize' => $this->perPage(),
'total' => $this->total(),
]
];
});
// 使用自定义方法
$users = User::paginate(15);
return $users->toCustomFormat();
🛠️ 实战案例:电商商品分页
<?php
namespace App\Controller;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use App\Service\ProductService;
#[Controller(prefix: "/api/products")]
class ProductController
{
public function __construct(private ProductService $productService) {}
#[GetMapping("")]
public function index()
{
$filters = [
'category' => request()->input('category'),
'price_min' => request()->input('price_min'),
'price_max' => request()->input('price_max'),
'sort' => request()->input('sort', 'created_at'),
'order' => request()->input('order', 'desc'),
];
$perPage = request()->input('per_page', 24);
$products = $this->productService->getPaginatedProducts($filters, $perPage);
// 定制分页响应
return [
'success' => true,
'data' => [
'products' => $products->items(),
'pagination' => [
'current_page' => $products->currentPage(),
'per_page' => $products->perPage(),
'total' => $products->total(),
'total_pages' => $products->lastPage(),
'links' => [
'first' => $products->url(1),
'last' => $products->url($products->lastPage()),
'prev' => $products->previousPageUrl(),
'next' => $products->nextPageUrl(),
]
],
'filters' => $filters
]
];
}
}
📝 最佳实践总结
分页器选择指南
| 场景 | 推荐分页器 | 理由 |
|---|---|---|
| 后台管理系统 | LengthAwarePaginator | 需要显示总数和总页数 |
| 移动端列表 | Paginator | 性能优先,避免COUNT查询 |
| 无限滚动 | 自定义游标分页 | 更好的用户体验 |
| 大数据量 | simplePaginate | 避免性能瓶颈 |
性能优化 checklist
- 避免N+1查询问题
- 合理使用索引加速分页
- 考虑使用缓存分页结果
- 大数据量时使用游标分页
- 监控分页查询性能
常见问题解决方案
问题1:分页性能慢
// 解决方案:添加合适索引并优化查询
DB::table('users')->where('status', 1)->orderBy('created_at')->paginate(15);
// 确保 status 和 created_at 有复合索引
问题2:分页URL参数丢失
// 解决方案:使用withQueryString方法
$users = User::paginate(15)->withQueryString();
问题3:自定义分页参数名
// 解决方案:设置自定义页码参数名
$users = User::paginate(15, ['*'], 'p', request()->input('p'));
🎯 总结
Hyperf分页器提供了强大而灵活的分页解决方案,从简单的数组分页到复杂的数据库分页,都能轻松应对。通过本文的学习,您应该能够:
- 掌握Hyperf分页器的核心概念和使用方法
- 实现各种场景下的数据分页需求
- 深度定制分页样式和响应格式
- 优化分页性能并提供更好的用户体验
- 解决分页过程中的常见问题
分页不仅仅是技术实现,更是用户体验的重要组成部分。合理运用Hyperf分页器的各种特性,将为您的应用带来更加流畅和高效的数据展示体验。
点赞/收藏/关注三连,获取更多Hyperf实战技巧!下期预告:《Hyperf数据库优化:从入门到精通》
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



