Laravel 大将之 分页 模块

简介

官方 API 地址 https://laravel.com/api/5.4/Illuminate/Pagination.html

分页模块的基本使用有两种:一种是基于查询构建器或Eloquent模型,调用paginate方法;另一种是手动创建分页器;

Laravel框架的分页器不仅实现了数据的分页,而且支持生成Bootstrap的分页框,如下图所示

使用

基于查询构建器或Eloquent模型

User表获取数据,每页16条,可以这样写

1
2
3
$users = DB::table('user')->paginate(16);
// 或
$users = User::paginate(16);

这时的$userIlluminate\Pagination\LengthAwarePaginator实例;这里没有传递当前页的原因是,如果不传递,会从$request请求获取当前页;
paginate方法完整参数定义如下:

1
paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)

其中 $perPage 代表每页显示数目, $columns 代表查询字段, $pageName 代表页码名称, $page 代表第几页。

同理,也可以获取另一种分页,简单分页

1
2
3
$users = DB::table('user')->simplePaginate(16);
// 或
$users = User::simplePaginate(16);

这时的$userIlluminate\Pagination\Paginator实例;

要想在页面呈现分页器的小方块, 只要在blade.php 中书写

1
{!! $users->render() !!}

手动创建

通过看看LaravelDatabase是怎么实现创建分页器,更好地学会使用手动创建;
先看看paginate方法,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)   
{
// 获取当前页数
$page = $page ?: Paginator::resolveCurrentPage($pageName);
// 获取每页的数量
$perPage = $perPage ?: $this->model->getPerPage();
// Collection类,存放当前页的数据记录
$results = ($total = $this->toBase()->getCountForPagination())
? $this->forPage($page, $perPage)->get($columns)
: $this->model->newCollection();

return new LengthAwarePaginator($results, $total, $perPage, $page, [
// 当前页面的 url
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}

再看看simplePaginate方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
// 获取当前页数
$page = $page ?: Paginator::resolveCurrentPage($pageName);
// 获取每页的数量
$perPage = $perPage ?: $this->model->getPerPage();

// 调用 Database 模块当前类的方法,获取当前页的数据;
// 下面这个语句只是设置查询条件,get 方法调用时才是真正去获取
$this->skip(($page - 1) * $perPage)->take($perPage + 1);

return new Paginator($this->get($columns), $perPage, $page, [
// 当前页面的 url
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}

看看源代码

服务提供者 ServiceProvider

boot方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public function boot()
{
// 注册包视图
$this->loadViewsFrom(__DIR__.'/resources/views', 'pagination');

// 如果程序是在命令行下运行,则将模块内的`resources/views`文件夹下的文件
// 发布一份到项目的`views/vendor/pagination`文件夹;
// publishes 方法的第二个参数是 group 组;
if ($this->app->runningInConsole()) {
$this->publishes([
__DIR__.'/resources/views' => $this->app->resourcePath('views/vendor/pagination'),
], 'laravel-pagination');
}
}

register方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public function register()
{
// 绑定 view 视图解析器
Paginator::viewFactoryResolver(function () {
return $this->app['view'];
});

// 绑定 url 路径解析器,返回当前 url
Paginator::currentPathResolver(function () {
return $this->app['request']->url();
});

// 绑定 当前页 解析器,返回当前页
Paginator::currentPageResolver(function ($pageName = 'page') {
$page = $this->app['request']->input($pageName);

if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) {
return $page;
}

return 1;
});
}

分页器类有两个PaginatorLengthAwarePaginator,都继承了父类AbstractPaginator;两者的主要区别主要在于render方法,也就是呈现的bootstrap风格的分页器不一样;

Paginator的分页器,只有上一页和下一页的图标

LengthAwarePaginator的分页器