資料庫: 分頁
簡介
在其他框架中,分頁可能會讓人感到非常痛苦。我們希望 Laravel 對分頁的處理方式能帶來一絲清新的空氣。Laravel 的分頁器與 查詢生成器 和 Eloquent ORM 整合在一起,提供方便、易於使用的資料庫記錄分頁,而且無需任何配置。
預設情況下,分頁器生成的 HTML 與 Tailwind CSS 框架 兼容;但也提供 Bootstrap 分頁支持。
Tailwind JIT
如果您正在使用 Laravel 的預設 Tailwind 分頁視圖和 Tailwind JIT 引擎,請確保您應用程式的 tailwind.config.js
檔案的 content
關鍵字參考 Laravel 的分頁視圖,以便它們的 Tailwind 類別不會被清除:
content: [
'./resources/**/*.blade.php',
'./resources/**/*.js',
'./resources/**/*.vue',
'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
],
基本用法
對查詢生成器結果進行分頁
有幾種分頁項目的方法。最簡單的方法是在 查詢生成器 或 Eloquent 查詢 上使用 paginate
方法。paginate
方法會自動設置查詢的 "limit" 和 "offset",根據用戶查看的當前頁面。預設情況下,Laravel 會根據 HTTP 請求的 page
查詢字串參數的值來檢測當前頁面。這個值會被 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
方法在從資料庫檢索記錄之前計算查詢匹配的總記錄數。這樣做是為了讓分頁器知道總共有多少頁的記錄。然而,如果您不打算在應用程式的使用者介面中顯示總頁數,則記錄計數查詢是不必要的。
因此,如果您只需要在應用程式的使用者介面中顯示簡單的「下一頁」和「上一頁」連結,您可以使用 simplePaginate
方法執行單一且有效率的查詢:
$users = DB::table('users')->simplePaginate(15);
分頁 Eloquent 結果
您也可以對 Eloquent 查詢進行分頁。在這個範例中,我們將對 App\Models\User
模型進行分頁,並指定我們打算每頁顯示 15 條記錄。正如您所見,語法幾乎與對查詢構建器結果進行分頁的方式相同:
use App\Models\User;
$users = User::paginate(15);
當然,您可以在設定查詢的其他約束條件後調用 paginate
方法,例如 where
子句:
$users = User::where('votes', '>', 100)->paginate(15);
您也可以在對 Eloquent 模型進行分頁時使用 simplePaginate
方法:
$users = User::where('votes', '>', 100)->simplePaginate(15);
同樣地,您可以使用 cursorPaginate
方法來對 Eloquent 模型進行游標分頁:
$users = User::where('votes', '>', 100)->cursorPaginate(15);
每頁多個分頁器實例
有時您可能需要在應用程式呈現的單個畫面上呈現兩個獨立的分頁器。但是,如果兩個分頁器實例都使用 page
查詢字串參數來存儲當前頁面,這兩個分頁器將發生衝突。為了解決這個衝突,您可以通過提供給 paginate
、simplePaginate
和 cursorPaginate
方法的第三個引數來傳遞您希望使用的查詢字串參數的名稱來存儲分頁器的當前頁面:
游標分頁
雖然 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" 子句才能利用游標分頁。此外,查詢排序的列必須屬於您正在分頁的表。
游標 vs. 偏移分頁
為了說明偏移分頁和游標分頁之間的區別,讓我們來看一些示例 SQL 查詢。以下兩個查詢都將顯示按 id
排序的 users
表的 "第二頁" 結果:
# 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
值的欄位。 - 只有在為其取別名並將其添加到「select」子句中時,才支援「order by」子句中的查詢表達式。
- 不支援帶有參數的查詢表達式。
手動建立分頁器
有時您可能希望手動創建分頁實例,將您已經在記憶體中擁有的項目陣列傳遞給它。您可以通過創建 Illuminate\Pagination\Paginator
、Illuminate\Pagination\LengthAwarePaginator
或 Illuminate\Pagination\CursorPaginator
實例來實現這一點,具體取決於您的需求。
Paginator
和 CursorPaginator
類不需要知道結果集中項目的總數;然而,由於這一點,這些類別沒有檢索最後一頁索引的方法。LengthAwarePaginator
接受的參數幾乎與 Paginator
相同;但是,它需要結果集中項目的總數。
換句話說,Paginator
對應於查詢建構器上的 simplePaginate
方法,CursorPaginator
對應於 cursorPaginate
方法,而 LengthAwarePaginator
對應於 paginate
方法。
[!WARNING]
當手動建立分頁器實例時,您應該手動“切片”您傳遞給分頁器的結果陣列。如果您不確定如何執行此操作,請查看 array_slice PHP 函式。
自訂分頁網址
預設情況下,分頁器生成的連結將與當前請求的 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
方法生成的 HTML 與 Tailwind 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
等元信息。結果記錄可通過 JSON 陣列中的 data
鍵獲取。以下是通過從路由返回分頁器實例來創建的 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...
}
]
}
自定義分頁視圖
默認情況下,用於顯示分頁連結的視圖與 Tailwind 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。
如果您想要指定不同的檔案作為預設分頁視圖,您可以在 App\Providers\AppServiceProvider
類別的 boot
方法中調用分頁器的 defaultView
和 defaultSimpleView
方法:
<?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');
}
}
使用 Bootstrap
Laravel 包含使用 Bootstrap CSS 構建的分頁視圖。若要使用這些視圖而不是預設的 Tailwind 視圖,您可以在 App\Providers\AppServiceProvider
類別的 boot
方法中調用分頁器的 useBootstrapFour
或 useBootstrapFive
方法:
use Illuminate\Pagination\Paginator;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Paginator::useBootstrapFive();
Paginator::useBootstrapFour();
}
分頁器 / LengthAwarePaginator 實例方法
每個分頁器實例通過以下方法提供額外的分頁資訊: