数据库:分页
Introduction
在其他框架中,分页可能非常痛苦。我们希望 Laravel 的分页方法能带来新鲜空气。 Laravel 的分页器与查询生成器 和雄辩的ORM 并提供方便、易于使用的零配置数据库记录分页。
默认情况下,分页器生成的 HTML 与顺风 CSS 框架;但是,也可以使用 Bootstrap 分页支持。
顺风 JIT
如果你正在使用 Laravel 的默认 Tailwind 分页视图和 Tailwind JIT 引擎,你应该确保你的应用程序的tailwind.config.js
文件的content
key 引用 Laravel 的分页视图,这样它们的 Tailwind 类就不会被清除:
content: [
'./resources/**/*.blade.php',
'./resources/**/*.js',
'./resources/**/*.vue',
'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
],
基本用法
分页查询生成器结果
有几种方法可以对项目进行分页。最简单的是使用paginate
上的方法查询生成器 或一个雄辩的查询.这paginate
方法会根据用户正在查看的当前页面自动负责设置查询的“限制”和“偏移量”。默认情况下,当前页面由page
HTTP 请求的查询字符串参数。这个值会被 Laravel 自动检测到,也会自动插入到分页器生成的链接中。
在此示例中,传递给paginate
方法是您希望“每页”显示的项目数。在这种情况下,让我们指定我们想要显示15
每页项目:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
class UserController extends Controller
{
/**
* Show all application users.
*/
public function index(): View
{
return view('user.index', [
'users' => DB::table('users')->paginate(15)
]);
}
}
简单分页
这paginate
方法在从数据库中检索记录之前计算查询匹配的记录总数。这样做是为了让分页器知道总共有多少页记录。但是,如果您不打算在应用程序的 UI 中显示总页数,则记录计数查询是不必要的。
因此,如果您只需要在应用程序的 UI 中显示简单的“Next”和“Previous”链接,您可以使用simplePaginate
执行单个高效查询的方法:
$users = DB::table('users')->simplePaginate(15);
分页雄辩的结果
你也可以分页Eloquent 查询。在这个例子中,我们将分页App\Models\User
模型并表明我们计划每页显示 15 条记录。如您所见,语法几乎与分页查询生成器结果相同:
use App\Models\User;
$users = User::paginate(15);
当然,你可以调用paginate
在查询上设置其他约束后的方法,例如where
条款:
$users = User::where('votes', '>', 100)->paginate(15);
您也可以使用simplePaginate
分页 Eloquent 模型时的方法:
$users = User::where('votes', '>', 100)->simplePaginate(15);
同样,您可以使用cursorPaginate
光标分页 Eloquent 模型的方法:
$users = User::where('votes', '>', 100)->cursorPaginate(15);
每页多个分页器实例
有时您可能需要在应用程序呈现的单个屏幕上呈现两个独立的分页器。但是,如果两个分页器实例都使用page
查询字符串参数来存储当前页面,这两个分页器会冲突。要解决此冲突,您可以通过提供给paginate
,simplePaginate
, 和cursorPaginate
方法:
use App\Models\User;
$users = User::where('votes', '>', 100)->paginate(
$perPage = 15, $columns = ['*'], $pageName = 'users'
);
光标分页
尽管paginate
和simplePaginate
使用 SQL“offset”子句创建查询,游标分页通过构造“where”子句来工作,这些子句比较查询中包含的有序列的值,提供 Laravel 所有分页方法中可用的最有效的数据库性能。这种分页方法特别适合大型数据集和“无限”滚动用户界面。
与基于偏移量的分页不同,它在分页器生成的 URL 的查询字符串中包含页码,基于游标的分页在查询字符串中放置一个“游标”字符串。游标是一个编码字符串,包含下一个分页查询应该开始分页的位置和它应该分页的方向:
http://localhost/users?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0
您可以通过以下方式创建基于游标的分页器实例cursorPaginate
查询构建器提供的方法。该方法返回一个实例Illuminate\Pagination\CursorPaginator
:
$users = DB::table('users')->orderBy('id')->cursorPaginate(15);
检索到游标分页器实例后,您可以显示分页结果 就像您通常在使用paginate
和simplePaginate
方法。有关游标分页器提供的实例方法的更多信息,请参阅光标分页器实例方法文档.
Warning
您的查询必须包含“order by”子句才能利用游标分页。
光标与偏移分页
为了说明偏移分页和游标分页之间的差异,让我们检查一些示例 SQL 查询。以下两个查询都将显示结果的“第二页”users
表排序id
:
# Offset Pagination...
select * from users order by id asc limit 15 offset 15;
# Cursor Pagination...
select * from users where id > 15 order by id asc limit 15;
游标分页查询与偏移分页相比具有以下优点:
- 对于大型数据集,如果“order by”列被索引,游标分页将提供更好的性能。这是因为“offset”子句扫描了所有先前匹配的数据。
- 对于频繁写入的数据集,如果最近在用户当前查看的页面中添加或删除了结果,则偏移分页可能会跳过记录或显示重复项。
但是,游标分页有以下限制:
- 喜欢
simplePaginate
,光标分页只能用于显示“下一页”和“上一页”链接,不支持生成带页码的链接。 - 它要求排序至少基于一个唯一的列或一组唯一的列。列与
null
不支持值。 - “order by”子句中的查询表达式仅在它们具有别名并且也添加到“select”子句时才受支持。
- 不支持带参数的查询表达式。
手动创建分页器
有时您可能希望手动创建一个分页实例,将您已经在内存中的项目数组传递给它。您可以通过创建一个Illuminate\Pagination\Paginator
,Illuminate\Pagination\LengthAwarePaginator
或者Illuminate\Pagination\CursorPaginator
例如,取决于您的需要。
这Paginator
和CursorPaginator
类不需要知道结果集中的项目总数;然而,正因为如此,这些类没有检索最后一页索引的方法。这LengthAwarePaginator
接受与Paginator
;但是,它需要对结果集中的项目总数进行计数。
换句话说,Paginator
对应于simplePaginate
查询生成器上的方法,CursorPaginator
对应于cursorPaginate
方法,以及LengthAwarePaginator
对应于paginate
方法。
Warning
手动创建分页器实例时,您应该手动“切片”传递给分页器的结果数组。如果您不确定如何执行此操作,请查看array_slice PHP函数。
自定义分页 URL
默认情况下,分页器生成的链接将匹配当前请求的 URI。然而,分页器的withPath
方法允许您自定义分页器在生成链接时使用的 URI。例如,如果您希望分页器生成如下链接http://example.com/admin/users?page=N
,你应该通过/admin/users
到withPath
方法:
use App\Models\User;
Route::get('/users', function () {
$users = User::paginate(15);
$users->withPath('/admin/users');
// ...
});
附加查询字符串值
您可以使用appends
方法。例如,追加sort=votes
对于每个分页链接,您应该进行以下调用appends
:
use App\Models\User;
Route::get('/users', function () {
$users = User::paginate(15);
$users->appends(['sort' => 'votes']);
// ...
});
您可以使用withQueryString
如果您想将所有当前请求的查询字符串值附加到分页链接,请使用以下方法:
$users = User::paginate(15)->withQueryString();
附加哈希片段
如果您需要将“哈希片段”附加到分页器生成的 URL,您可以使用fragment
方法。例如,追加#users
到每个分页链接的末尾,您应该调用fragment
像这样的方法:
$users = User::paginate(15)->fragment('users');
显示分页结果
当调用paginate
方法,您将收到一个实例Illuminate\Pagination\LengthAwarePaginator
,同时调用simplePaginate
方法返回一个实例Illuminate\Pagination\Paginator
.最后,调用cursorPaginate
方法返回一个实例Illuminate\Pagination\CursorPaginator
.
这些对象提供了几种描述结果集的方法。除了这些辅助方法之外,分页器实例是迭代器,可以作为数组循环。因此,一旦检索到结果,就可以显示结果并使用以下方法呈现页面链接Blade:
<div class="container">
@foreach ($users as $user)
{{ $user->name }}
@endforeach
</div>
{{ $users->links() }}
这links
方法将呈现指向结果集中其余页面的链接。这些链接中的每一个都已经包含适当的page
查询字符串变量。请记住,由links
方法兼容顺风 CSS 框架.
调整分页链接窗口
当分页器显示分页链接时,会显示当前页码以及当前页前后三页的链接。使用onEachSide
方法,您可以控制在分页器生成的链接的中间滑动窗口中当前页面的每一侧显示多少个附加链接:
{{ $users->onEachSide(5)->links() }}
将结果转换为 JSON
Laravel 分页器类实现了Illuminate\Contracts\Support\Jsonable
接口契约并公开toJson
方法,因此很容易将分页结果转换为 JSON。您还可以通过从路由或控制器操作返回它来将分页器实例转换为 JSON:
use App\Models\User;
Route::get('/users', function () {
return User::paginate();
});
来自分页器的 JSON 将包含元信息,例如total
,current_page
,last_page
, 和更多。结果记录可通过data
JSON 数组中的键。以下是通过从路由返回分页器实例创建的 JSON 示例:
{
"total": 50,
"per_page": 15,
"current_page": 1,
"last_page": 4,
"first_page_url": "http://laravel.app?page=1",
"last_page_url": "http://laravel.app?page=4",
"next_page_url": "http://laravel.app?page=2",
"prev_page_url": null,
"path": "http://laravel.app",
"from": 1,
"to": 15,
"data":[
{
// Record...
},
{
// Record...
}
]
}
自定义分页视图
默认情况下,显示分页链接的视图与顺风 CSS 框架。但是,如果您不使用 Tailwind,您可以自由定义自己的视图来呈现这些链接。当调用links
分页器实例上的方法,您可以将视图名称作为第一个参数传递给该方法:
{{ $paginator->links('view.name') }}
<!-- Passing additional data to the view... -->
{{ $paginator->links('view.name', ['foo' => 'bar']) }}
但是,自定义分页视图的最简单方法是将它们导出到您的resources/views/vendor
目录使用vendor:publish
命令:
php artisan vendor:publish --tag=laravel-pagination
此命令会将视图放置在您的应用程序的resources/views/vendor/pagination
目录。这tailwind.blade.php
此目录中的文件对应于默认分页视图。您可以编辑此文件以修改分页 HTML。
如果你想指定一个不同的文件作为默认分页视图,你可以调用分页器的defaultView
和defaultSimpleView
中的方法boot
你的方法App\Providers\AppServiceProvider
班级:
<?php
namespace App\Providers;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Paginator::defaultView('view-name');
Paginator::defaultSimpleView('view-name');
}
}
使用引导程序
Laravel 包括使用构建的分页视图引导 CSS.要使用这些视图而不是默认的 Tailwind 视图,您可以调用分页器的useBootstrapFour
或者useBootstrapFive
中的方法boot
你的方法App\Providers\AppServiceProvider
班级:
use Illuminate\Pagination\Paginator;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Paginator::useBootstrapFive();
Paginator::useBootstrapFour();
}
分页器/LengthAwarePaginator 实例方法
每个分页器实例通过以下方法提供额外的分页信息:
Method | Description |
---|---|
$paginator->count() |
获取当前页面的项目数。 |
$paginator->currentPage() |
获取当前页码。 |
$paginator->firstItem() |
获取结果中第一项的结果编号。 |
$paginator->getOptions() |
获取分页器选项。 |
$paginator->getUrlRange($start, $end) |
创建一系列分页 URL。 |
$paginator->hasPages() |
确定是否有足够的项目拆分成多个页面。 |
$paginator->hasMorePages() |
确定数据存储中是否还有更多项目。 |
$paginator->items() |
获取当前页面的项目。 |
$paginator->lastItem() |
获取结果中最后一项的结果编号。 |
$paginator->lastPage() |
获取最后可用页面的页码。 (使用时不可用simplePaginate ). |
$paginator->nextPageUrl() |
获取下一页的 URL。 |
$paginator->onFirstPage() |
确定分页器是否在第一页上。 |
$paginator->perPage() |
每页显示的项目数。 |
$paginator->previousPageUrl() |
获取上一页的 URL。 |
$paginator->total() |
确定数据存储中匹配项的总数。 (使用时不可用simplePaginate ). |
$paginator->url($page) |
获取给定页码的 URL。 |
$paginator->getPageName() |
获取用于存储页面的查询字符串变量。 |
$paginator->setPageName($name) |
设置用于存储页面的查询字符串变量。 |
游标分页器实例方法
每个游标分页器实例通过以下方法提供额外的分页信息:
Method | Description |
---|---|
$paginator->count() |
获取当前页面的项目数。 |
$paginator->cursor() |
获取当前游标实例。 |
$paginator->getOptions() |
获取分页器选项。 |
$paginator->hasPages() |
确定是否有足够的项目拆分成多个页面。 |
$paginator->hasMorePages() |
确定数据存储中是否还有更多项目。 |
$paginator->getCursorName() |
获取用于存储游标的查询字符串变量。 |
$paginator->items() |
获取当前页面的项目。 |
$paginator->nextCursor() |
获取下一组项目的游标实例。 |
$paginator->nextPageUrl() |
获取下一页的 URL。 |
$paginator->onFirstPage() |
确定分页器是否在第一页上。 |
$paginator->onLastPage() |
确定分页器是否在最后一页。 |
$paginator->perPage() |
每页显示的项目数。 |
$paginator->previousCursor() |
获取上一组项目的游标实例。 |
$paginator->previousPageUrl() |
获取上一页的 URL。 |
$paginator->setCursorName() |
设置用于存储游标的查询字符串变量。 |
$paginator->url($cursor) |
获取给定游标实例的 URL。 |