首页 >后端开发 >php教程 >Laravel的分页指南

Laravel的分页指南

Johnathan Smith
Johnathan Smith原创
2025-03-06 02:04:09637浏览

分页是Web应用程序中的常见功能。我从事过的几乎所有Laravel应用程序都实施了某种形式的分页。

但是什么是分页,为什么要使用它?我们如何在Laravel应用程序中实施分页?我们如何决定要使用哪种分页方法? 在本文中,我们将回答这些问题,并探索如何在Laravel中使用分页来获得刀片视图和API端点。到本文结束时,您应该有足够的信心开始在自己的项目中使用分页。

#什么是分页?

分页是一种用于将大数据集分为较小块(或页面)的技术。它允许您显示数据的一个子集,而不是一次显示所有可能的值。

> 例如,想象一下,您有一个页面,可以输出应用程序中所有用户的名称。如果您有成千上万的用户,则将所有用户全部显示在单个页面上是不切实际的。取而代之的是,您可以使用分页来在每个页面上显示一个用户的子集(例如10个用户),并允许用户在页面之间导航以查看更多用户(下一个10)。

通过使用分页,您可以:>

>提高应用程序的性能 - 由于您一次获取较小的数据子集,因此您可以从数据库中获取的数据更少,然后返回。

改善用户体验 - 用户一次只能一次对一小部分数据感兴趣(通常在前几页中找到,尤其是在使用过滤器和搜索词时)。通过使用分页,您可以避免显示用户不感兴趣的数据。

>

改进页面加载时间 - 仅一次获取数据的子集,您可以减少需要加载到页面上的数据量,从而可以改善页面加载和JavaScript处理时间。

>

分页通常可以分为两种不同的类型:

>

基于偏移的分页 - 这是您可能会在Web应用程序中遇到的最常见的分页类型,尤其是在用户界面(UI)中。它涉及基于“偏移”和“限制”从数据库中获取数据库的子集。例如,您可能会从第20个记录开始获取10个记录,以获取数据的第三页。
    基于光标的分页 - 这种类型的分页涉及根据“光标”获取数据子集。光标通常是数据库中记录的唯一标识符。例如,您可以从记录开始的下一个10个记录中获取ID 20的记录。
  • Laravel提供了三种不同的方法,用于在您的应用程序中使用雄辩的查询:
    • paginate - 使用基于偏移的分页并获取数据集中的记录总数。>
    • - 使用基于偏移的分页,但没有获取数据集中的记录总数。> simplePaginate
    • - 使用基于光标的分页,并且不会获取数据集中的记录总数。>
    • cursorPaginate>让我们更详细地看一下这些方法。
    • >
    #use

    方法

    paginate方法允许您根据偏移和限制从数据库中获取数据子集(当我们查看基础SQL查询时,我们将在稍后查看这些数据库)。

    您可以使用这样的方法:

    paginate

    >运行上述代码将导致

    >是paginate的实例,通常是

    >对象。此Paginator实例包含您需要在应用程序中显示分页数据的所有信息。>
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    
    $users = User::query()->paginate();
    

    方法可以根据URL中的$users查询参数自动确定所请求的页码。例如,如果您访问了IlluminateContractsPaginationLengthAwarePaginatorIlluminatePaginationLengthAwarePaginator方法将获取数据的第二页。 默认情况下,Laravel默认情况下的所有分页方法一次都以一次获取15个记录。但是,这可以将其更改为不同的值(我们将稍后再看一下)。

    >

    #usingpaginate带有刀片视图page https://my-app.com/users?page=2>让我们看一下在刀片视图中呈现数据时如何使用paginate的方法。

    想象我们有一条简单的路由,可以以分页格式从数据库中获取用户,并将其传递给视图:

    paginate我们的

    文件可能看起来像这样:

    > paginate

    结果页面看起来像这样:

    >

    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('users', function () {
        $users = User::query()->paginate();
    
        return view('users.index', [
            'users' => $users,
        ]);
    });
    

    resources/views/users/index.blade.php

    >让我们分解刀片视图中发生的事情:
    <!-- Syntax highlighted by torchlight.dev --><html>
    <head>
        <title>Paginate</title>
        <script src="https://cdn.tailwindcss.com"></script>
    </head>
    
    <body>
        <div class="max-w-5xl mx-auto py-8">
            <h1 class="text-5xl">Paginate</h1>
    
            <ul class="py-4">
                @foreach ($users as $user)
                    <li class="py-1 border-b">{{ $user->name }}</li>
                @endforeach
            </ul>
    
            {{ $users->links() }}
        </div>
    </body>
    </html>
    
    • >我们正在循环浏览$users字段中存在的每个用户(IlluminatePaginationLengthAwarePaginator>对象)并输出其名称。
    • >
    • >我们在对象上调用links>方法。这是一种非常方便的方法,它返回一些显示分页链接的HTML(例如“上一个”,“下一个”和页码)。这意味着您不必担心自己创建分页链接,而Laravel会为您处理所有这些。$users
    >我们还可以看到,

    方法正在为我们提供分页数据的概述。我们可以看到,我们正在查看第16至30个记录,总共有50个记录。我们还可以看到我们在第二页上,总共有4页。 paginate>重要的是要注意,

    >方法将使用尾风CSS返回HTML样式。如果您想使用除尾风以外的其他东西,或者想自己设置分页链接,则可以查看有关自定义分页视图的文档。

    > links #using

    在API端点

    paginate以及在刀片视图中使用

    方法,您也可以在API端点中使用它。 Laravel通过将分页的数据自动转换为JSON,使此过程变得容易。端点(通过将以下路由添加到我们的paginate文件),该端口以JSON格式返回了分页的用户:>

    >访问/api/users端点将返回类似于以下的JSON响应(请注意,出于简洁起见,我将routes/api.php>字段限制为3个记录):>

    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    
    $users = User::query()->paginate();
    
    让我们分解JSON响应:

    • current_page - 我们正在使用的当前页面。在这种情况下,我们在第一页上。
    • data - 正在返回的实际数据本身。在这种情况下,它包含前15位用户(简短为3个用户)。
    • >
    • first_page_url - 数据的第一页的URL。
    • >
    • from - 返回数据的起始记录号。在这种情况下,这是第一个记录。如果我们在第二页上,那将是16。
    • - 数据的总数。在这种情况下,有4页。last_page
    • - 数据的最后一页的URL。last_page_url>
    • - 指向数据不同页面的链接数组。这包括“上一个”和“下一个”链接以及页码。links>
    • - 数据的下一页的URL。 next_page_url
    • - 端点的基本URL。
    • > path
    • - 每页返回的记录数。在这种情况下,是15。
    • per_page - 数据的上一页的URL。在这种情况下,这是
    • ,因为我们在第一页上。如果我们在第二页上,这将是第一页的URL。
    • > prev_page_urlnull - 返回数据的结尾记录号。在这种情况下,这是第15张记录。如果我们在第二页上,那将是30。
    • - 数据集中的记录总数。在这种情况下,有50个记录。to
    • #基础SQL查询total
    • 在Laravel中使用
    方法会导致两个SQL查询正在运行:

    第一个查询获取数据集中的记录总数。这用于确定信息,例如页面总数和记录总数。 paginate第二个查询根据偏移和限制值获取数据子集。例如,它可能正在获取用户以供我们处理和返回。

    >
    • >因此,如果我们想获取用户的第一页(每个页面有15个用户),则将运行以下SQL查询:
    • >

    在第二个查询中,我们可以看到
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    
    $users = User::query()->paginate();
    
    值设置为15。这是每页返回的记录数。

    >

    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('users', function () {
        $users = User::query()->paginate();
    
        return view('users.index', [
            'users' => $users,
        ]);
    });
    
    值的计算如下:

    > limit

    >因此,如果我们想获取用户的第三页,则

    的值将计算为:offset>

    <!-- Syntax highlighted by torchlight.dev --><html>
    <head>
        <title>Paginate</title>
        <script src="https://cdn.tailwindcss.com"></script>
    </head>
    
    <body>
        <div class="max-w-5xl mx-auto py-8">
            <h1 class="text-5xl">Paginate</h1>
    
            <ul class="py-4">
                @foreach ($users as $user)
                    <li class="py-1 border-b">{{ $user->name }}</li>
                @endforeach
            </ul>
    
            {{ $users->links() }}
        </div>
    </body>
    </html>
    
    >因此,

    值将为30,我们将获取第31到第45个记录。第三页的查询看起来像:offset

    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('paginate', function () {
        return User::query()->paginate();
    });
    

    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    
    $users = User::query()->paginate();
    

    #use simplePaginate方法

    simplePaginate方法与paginate方法非常相似,但具有一个关键差异。该方法未获取数据集中的记录总数。simplePaginate> 正如我们刚刚看到的那样,当我们使用

    方法时,我们还会获取有关数据集中可用的记录总数和页面的信息。然后,我们可以使用此信息来显示诸如UI或API响应中的页面总数等内容。

    > paginate>但是,如果您不打算向用户(或消耗API的开发人员)显示这些详细信息,那么我们可以使用

    >

    >simplePaginate>来避免不需要的数据库查询(计算记录总数)。

    方法可以与simplePaginate方法相同的方式使用:paginate>

    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('users', function () {
        $users = User::query()->paginate();
    
        return view('users.index', [
            'users' => $users,
        ]);
    });
    
    运行上述代码将导致

    的实例,通常为$users>对象。 IlluminateContractsPaginationPaginator>与IlluminatePaginationPaginator方法返回的对象不同,

    >对象不包含有关数据集中记录总数的信息,也不知道有多少页或总记录。它只知道当前数据页面以及是否还有更多记录可以获取。

    > IlluminatePaginationLengthAwarePaginator #usingpaginate带有刀片视图IlluminatePaginationPaginator

    >让我们看一下如何使用刀片视图的方法。我们假设我们有与以前相同的路线,但是这次我们使用的

    方法:> simplePaginate

    我们将以与以前相同的方式构建刀片视图:

    > simplePaginate simplePaginate结果页面看起来像这样:

    >
    <!-- Syntax highlighted by torchlight.dev --><html>
    <head>
        <title>Paginate</title>
        <script src="https://cdn.tailwindcss.com"></script>
    </head>
    
    <body>
        <div class="max-w-5xl mx-auto py-8">
            <h1 class="text-5xl">Paginate</h1>
    
            <ul class="py-4">
                @foreach ($users as $user)
                    <li class="py-1 border-b">{{ $user->name }}</li>
                @endforeach
            </ul>
    
            {{ $users->links() }}
        </div>
    </body>
    </html>
    

    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('paginate', function () {
        return User::query()->paginate();
    });
    
    正如我们在此示例中所看到的那样,

    >的输出与使用

    >方法时看到的输出不同。由于该方法没有获取记录总数,因此它没有页面或记录总数的上下文,只有下一页是否存在。因此,我们仅在分页链接中看到“上一个”和“下一个”链接。

    > #using在API端点

    >您也可以在API端点中使用$users->links()>方法。 Laravel将自动将分页数据转换为您的JSON。 paginate>让我们构建一个simplePaginate端点,以JSON格式返回分页的用户:

    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    
    $users = User::query()->paginate();
    

    >当我们碰到这条路线时,我们将获得类似于以下内容的JSON响应(我将data>字段限制为仅3个记录的简短):

    >
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('users', function () {
        $users = User::query()->paginate();
    
        return view('users.index', [
            'users' => $users,
        ]);
    });
    
    如我们所见,JSON响应与使用

    >方法时得到的响应非常相似。关键区别在于,我们没有响应中的paginatelast_pagelast_page_url>字段。linkstotal#基础SQL查询

    >让我们看一下使用

    >方法时运行的基础SQL查询。

    simplePaginate

    方法仍然依赖于

    simplePaginate>值来获取数据库的数据子集。但是,它没有运行查询来获取数据集中的记录总数。> limitoffset值仍以与以前相同的方式计算:

    >

    但是,offset值的计算略有不同。它被计算为:

    <!-- Syntax highlighted by torchlight.dev --><html>
    <head>
        <title>Paginate</title>
        <script src="https://cdn.tailwindcss.com"></script>
    </head>
    
    <body>
        <div class="max-w-5xl mx-auto py-8">
            <h1 class="text-5xl">Paginate</h1>
    
            <ul class="py-4">
                @foreach ($users as $user)
                    <li class="py-1 border-b">{{ $user->name }}</li>
                @endforeach
            </ul>
    
            {{ $users->links() }}
        </div>
    </body>
    </html>
    

    这是因为limit>方法需要比paginate值更多的记录来确定是否有更多记录可以获取。例如,假设我们每页获取15个记录。

    >值将为16。因此,如果要返回16个记录,我们知道至少还有一页可以获取的数据。如果返回了少于16个记录,我们会知道我们在数据的最后一页。
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('paginate', function () {
        return User::query()->paginate();
    });
    
    >因此,如果我们想获取用户的第一页(每个页面有15个用户),则将运行以下SQL查询:

    > simplePaginate perPage第二页的查询看起来像:limit

    #use

    方法
    <!-- Syntax highlighted by torchlight.dev -->{
      "current_page": 1,
      "data": [
        {
          "id": 1,
          "name": "Andy Runolfsson",
          "email": "teresa.wiegand@example.net",
          "email_verified_at": "2024-10-15T23:19:28.000000Z",
          "created_at": "2024-10-15T23:19:29.000000Z",
          "updated_at": "2024-10-15T23:19:29.000000Z"
        },
        {
          "id": 2,
          "name": "Rafael Cummings",
          "email": "odessa54@example.org",
          "email_verified_at": "2024-10-15T23:19:28.000000Z",
          "created_at": "2024-10-15T23:19:29.000000Z",
          "updated_at": "2024-10-15T23:19:29.000000Z"
        },
        {
          "id": 3,
          "name": "Reynold Lindgren",
          "email": "juwan.johns@example.net",
          "email_verified_at": "2024-10-15T23:19:28.000000Z",
          "created_at": "2024-10-15T23:19:29.000000Z",
          "updated_at": "2024-10-15T23:19:29.000000Z"
        }
      ],
      "first_page_url": "http://example.com/users?page=1",
      "from": 1,
      "last_page": 4,
      "last_page_url": "http://example.com/users?page=4",
      "links": [
        {
          "url": null,
          "label": "&laquo; Previous",
          "active": false
        },
        {
          "url": "http://example.com/users?page=1",
          "label": "1",
          "active": true
        },
        {
          "url": "http://example.com/users?page=2",
          "label": "2",
          "active": false
        },
        {
          "url": "http://example.com/users?page=3",
          "label": "3",
          "active": false
        },
        {
          "url": "http://example.com/users?page=4",
          "label": "4",
          "active": false
        },
        {
          "url": "http://example.com/users?page=5",
          "label": "5",
          "active": false
        },
        {
          "url": "http://example.com/users?page=2",
          "label": "Next &raquo;",
          "active": false
        }
      ],
      "next_page_url": "http://example.com/users?page=2",
      "path": "http://example.com/users",
      "per_page": 15,
      "prev_page_url": null,
      "to": 15,
      "total": 50
    }
    
    到目前为止,我们已经研究了

    >和

    的方法,这些方法都使用了基于偏移的分页。现在,我们将查看使用基于光标的分页的
    <!-- Syntax highlighted by torchlight.dev -->select count(*) as aggregate from `users`
    
    >方法。

    > cursorPaginate作为一个头部,基于光标的分页似乎有些混乱,当您第一次遇到它时。因此,如果您不立即将其拿走,请不要担心。希望在本文结尾,您将对它的工作原理有了更好的了解。我还将在本文的末尾留下一个很棒的视频,该视频更详细地解释了基于光标的分页。

    >

    >使用基于偏移的分页,我们使用paginatesimplePaginate>值从数据库中获取数据子集。因此,我们可以说“跳过前10个记录并获取接下来的10个记录”。这很容易理解且易于实现。尽管使用光标分页,我们使用光标(通常是数据库中特定记录的唯一标识符)作为获取上一组/下一组记录的起点。例如,假设我们要查询以获取前15个用户。我们假设第15个用户的ID为20。当我们要获取接下来的15个用户时,我们将使用第15用户(20)的ID作为光标。我们将说“获取接下来的15个用户,ID大于20”。

    >

    >您有时可能会看到光标称为“令牌”,“键”,“下一步”,“上一个”等。它们本质上是对数据库中特定记录的参考。当我们查看基础SQL查询时,我们将在本节中稍后查看光标的结构。

    laravel允许我们轻松地使用基于光标的分页来使用

    >:> cursorPaginate

    >运行上述代码将导致字段是<!-- Syntax highlighted by torchlight.dev -->use App\Models\User; $users = User::query()->paginate(); >对象。此Paginator实例包含您需要在应用程序中显示分页数据的所有信息。>

    >类似于$users>方法,该方法不会获取数据集中的记录总数。它仅知道当前数据页面以及是否还有更多记录需要获取,因此我们不立即意识到页面或记录的总数。IlluminateContractsPaginationCursorPaginator> IlluminatePaginationCursorPaginator #using

    带有刀片视图

    simplePaginate>让我们看一下如何在刀片视图中呈现数据时如何使用cursorPaginate的方法。与我们以前的示例类似,我们假设我们有一条简单的路由,可以以分页的格式从数据库中获取用户,并将其传递给视图:

    cursorPaginate刀片视图可能看起来像这样:

    cursorPaginate这将输出一个类似于以下几个页面:

    >
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('users', function () {
        $users = User::query()->paginate();
    
        return view('users.index', [
            'users' => $users,
        ]);
    });
    

    <!-- Syntax highlighted by torchlight.dev --><html>
    <head>
        <title>Paginate</title>
        <script src="https://cdn.tailwindcss.com"></script>
    </head>
    
    <body>
        <div class="max-w-5xl mx-auto py-8">
            <h1 class="text-5xl">Paginate</h1>
    
            <ul class="py-4">
                @foreach ($users as $user)
                    <li class="py-1 border-b">{{ $user->name }}</li>
                @endforeach
            </ul>
    
            {{ $users->links() }}
        </div>
    </body>
    </html>
    
    正如我们所能看到的,由于

    方法没有获取数据集中的记录总数,因此的输出与使用

    >方法时看到的输出相似。我们仅在分页链接中看到“上一个”和“下一个”链接。

    #using在API端点中

    laravel还允许您在API端点中使用

    >方法,并将自动将页上的数据转换为我们的JSON。 cursorPaginate>让我们构建一个$users->links()端点,以JSON格式返回分页的用户:simplePaginate

    >当我们碰到这条路线时,我们将获得类似于以下内容的JSON响应(我将cursorPaginate>字段限制为仅3个记录的简短):

    >
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    
    $users = User::query()->paginate();
    
    如我们所见,JSON响应类似于我们看到的先前响应,但差异很小。由于我们没有获取记录的总数,因此我们没有响应中的

    字段。您可能还注意到我们也没有last_pagelast_page_url>字段。links> 相反,我们有total>和from>字段,该字段包含数据的下一个和上一个数据页面的光标。由于我们在第一页上,因此to

    字段均为

    >。但是,设置了next_cursorprev_cursor字段。prev_cursor> prev_page_urlnull字段是一个基本-64编码的字符串,其中包含数据的下一页的光标。如果我们解码next_cursor>字段,我们会得到这样的东西(为可读性而美化):> next_page_url

    光标包含两个单独的信息:

    next_cursor next_cursor

    - 数据集中获取的最后一个记录的ID。
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('users', function () {
        $users = User::query()->paginate();
    
        return view('users.index', [
            'users' => $users,
        ]);
    });
    
    >

    - 一个布尔值告诉我们光标是指向下一组还是上一组项目。如果值为
      >,则意味着光标应用于获取ID大于
    • >值的下一组记录。如果该值为users.id,则意味着光标应用于以ID小于
    • value的ID进行以下记录集。>。
    • _pointsToNextItems>让我们看一下数据的第二页可能是什么样子(再次缩短到3个记录,以简化):true users.id false我们可以看到现在设置了users.id
    • >字段,并且已使用光标更新了数据的下一页。
    #基础SQL查询

    为了更好地了解光标分页在引擎盖下的工作方式,让我们看一下使用
    <!-- Syntax highlighted by torchlight.dev --><html>
    <head>
        <title>Paginate</title>
        <script src="https://cdn.tailwindcss.com"></script>
    </head>
    
    <body>
        <div class="max-w-5xl mx-auto py-8">
            <h1 class="text-5xl">Paginate</h1>
    
            <ul class="py-4">
                @foreach ($users as $user)
                    <li class="py-1 border-b">{{ $user->name }}</li>
                @endforeach
            </ul>
    
            {{ $users->links() }}
        </div>
    </body>
    </html>
    
    >方法时运行的基础SQL查询。 在数据的第一页上(包含15个记录),将运行以下SQL查询:>

    prev_cursor>我们可以看到,我们正在从prev_page_url>表中获取前16个记录,并按next_cursor列以升序顺序订购。与next_page_url方法相似,我们要提取16行,因为我们想确定是否还有更多记录可以获取。

    >

    >让我们想象我们然后通过以下光标导航到项目的下一页:>

    当该光标被解码时,我们会得到以下JSON对象: cursorPaginate 然后,Laravel将运行以下SQL查询以获取下一组记录:>

    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    
    $users = User::query()->paginate();
    
    如我们所见,我们从

    >表中获取了下一16个记录,该记录大于15(因为15是上一页的最后一个ID)。 users现在,让我们假设第2页上的第一个用户的ID是16。当我们从第二页导航回数据的第一页时,将使用以下光标: id

    解码时,我们将获得以下JSON对象:

    >当我们转到结果的下一页时,获取的最后一个记录被用作光标。当我们返回结果的上一页时,获取的第一个记录被用作光标。因此,我们可以看到在光标中设置为16。我们还可以看到
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('users', function () {
        $users = User::query()->paginate();
    
        return view('users.index', [
            'users' => $users,
        ]);
    });
    
    >值设置为

    ,因为我们正在回到先前的项目。

    。 结果,将运行以下SQL查询以获取先前的记录集:>
    <!-- Syntax highlighted by torchlight.dev --><html>
    <head>
        <title>Paginate</title>
        <script src="https://cdn.tailwindcss.com"></script>
    </head>
    
    <body>
        <div class="max-w-5xl mx-auto py-8">
            <h1 class="text-5xl">Paginate</h1>
    
            <ul class="py-4">
                @foreach ($users as $user)
                    <li class="py-1 border-b">{{ $user->name }}</li>
                @endforeach
            </ul>
    
            {{ $users->links() }}
        </div>
    </body>
    </html>
    

    >正如我们所看到的,users.id约束现在正在检查_pointsToNextItems少于16的记录(因为第2页上的第一个ID是16个),并且结果以降序排序。 false#使用分页的API资源

    到目前为止,在我们的API示例中,我们刚刚直接从控制器返回了分页数据。但是,在现实世界中,您可能需要在将数据返回给用户之前处理。这可能是从添加或删除字段,转换数据类型甚至将数据完全转换为不同格式的任何方法。因此,您可能需要使用API​​资源,因为它们为您提供了一种在返回数据之前始终转换数据的方法。

    Laravel

    允许您在分页上使用API​​资源。让我们看一个如何做的示例。
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('paginate', function () {
        return User::query()->paginate();
    });
    
    >

    想象我们已经创建了一个API资源类,该类别在返回之前会转换用户数据。它看起来像这样:where id

    >在

    >方法中,我们定义,每当我们通过此资源处理用户时,我们只想返回

    >,

    > fields。

    现在,让我们在我们的

    >文件中构建一个简单的API端点,该文件使用

    AppHttpResourcesUserResource返回了分页的用户

    <!-- Syntax highlighted by torchlight.dev -->{
      "current_page": 1,
      "data": [
        {
          "id": 1,
          "name": "Andy Runolfsson",
          "email": "teresa.wiegand@example.net",
          "email_verified_at": "2024-10-15T23:19:28.000000Z",
          "created_at": "2024-10-15T23:19:29.000000Z",
          "updated_at": "2024-10-15T23:19:29.000000Z"
        },
        {
          "id": 2,
          "name": "Rafael Cummings",
          "email": "odessa54@example.org",
          "email_verified_at": "2024-10-15T23:19:28.000000Z",
          "created_at": "2024-10-15T23:19:29.000000Z",
          "updated_at": "2024-10-15T23:19:29.000000Z"
        },
        {
          "id": 3,
          "name": "Reynold Lindgren",
          "email": "juwan.johns@example.net",
          "email_verified_at": "2024-10-15T23:19:28.000000Z",
          "created_at": "2024-10-15T23:19:29.000000Z",
          "updated_at": "2024-10-15T23:19:29.000000Z"
        }
      ],
      "first_page_url": "http://example.com/users?page=1",
      "from": 1,
      "last_page": 4,
      "last_page_url": "http://example.com/users?page=4",
      "links": [
        {
          "url": null,
          "label": "&laquo; Previous",
          "active": false
        },
        {
          "url": "http://example.com/users?page=1",
          "label": "1",
          "active": true
        },
        {
          "url": "http://example.com/users?page=2",
          "label": "2",
          "active": false
        },
        {
          "url": "http://example.com/users?page=3",
          "label": "3",
          "active": false
        },
        {
          "url": "http://example.com/users?page=4",
          "label": "4",
          "active": false
        },
        {
          "url": "http://example.com/users?page=5",
          "label": "5",
          "active": false
        },
        {
          "url": "http://example.com/users?page=2",
          "label": "Next &raquo;",
          "active": false
        }
      ],
      "next_page_url": "http://example.com/users?page=2",
      "path": "http://example.com/users",
      "per_page": 15,
      "prev_page_url": null,
      "to": 15,
      "total": 50
    }
    
    >在上面的代码中,我们从数据库中获取了一个用户(假设它是包含15个用户的第一页)的单个页面。然后,我们将

    字段(将是toArray>的实例)传递给id>方法。此方法将在将其退还给用户之前使用name转换分页的数据。

    >当我们击中/api/users端点时,我们将获得类似于以下内容的JSON响应(我将data>字段限制为仅3个记录的简短记录):

    >
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    
    $users = User::query()->paginate();
    
    正如我们在上面的JSON中看到的那样,Laravel检测到我们正在使用分页数据集,并以与以前相似的格式返回分页数据。但是,这一次,

    >字段中的用户仅包含我们在API资源类中指定的data>,idname>字段。其他字段(emailcurrent_pagefromlast_pagelinkspathper_pagetototal)仍被返回,因为它们是分页数据的一部分,但它们已放置在meta>字段中。还有一个包含linksfirstlast的字段,prev>链接到数据的不同页面。 next #Changing每个页面值

    >使用分页数据构建视图时,您可能需要允许用户更改每个页面显示的记录数量。这可能是通过下拉列表或数字输入字段。

    > Laravel使通过将A

    >参数传递到

    >,

    perPage>方法来更改每个页面显示的记录数量变得容易。此参数允许您指定要显示每个页面的记录数。simplePaginate> paginate>让我们看一个简单的示例,说明如何读取acursorPaginate查询参数并使用它来更改每页获取的记录数量:

    per_page在上面的示例中,我们正在抓取

    QUERY参数的值。如果未提供该值,我们将默认为10。然后,我们将该值传递给
    <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
    use Illuminate\Support\Facades\Route;
    
    Route::get('users', function () {
        $users = User::query()->paginate();
    
        return view('users.index', [
            'users' => $users,
        ]);
    });
    
    >方法的

    参数。 然后,我们可以访问这些不同的URL:> per_page perPagepaginate - 显示用户的第一页,每页10个记录。>

    - 显示用户的首页,每页5个记录。>

      - 显示用户的第二页,每页5个记录。>
    • 等等...https://my-app.com/users
    • #如何决定要使用哪种分页方法https://my-app.com/users?per_page=5
    • >现在我们已经研究了分页的不同类型以及如何在Laravel中使用它们,我们将讨论如何确定在您的应用程序中使用的哪种方法。>
    • #do您需要页码或记录总数?https://my-app.com/users?per_page=5&page=2>
    • 如果您要构建需要显示的记录或页面总数或页面的UI或API端点,则
    • >方法可能是一个明智的选择。
    • >

      如果您不需要任何一个,则simplePaginatecursorPaginate将会更有效,因为它们没有执行不必要的查询来计算记录总数。>

      #do您需要跳到特定页面?

      >

      如果您需要能够跳到特定的数据页面,则基于偏移的分页更合适。由于光标分页是有状态的,因此它依靠上一页知道下一步要去哪里。因此,跳到特定页面并不容易。

      >

      >使用偏移分页时,您通常只需传递请求中的页码(也许作为查询参数),然后跳到该页面而不具有上一页的任何上下文。

      #wath是多大的数据集?

      >

      由于数据库处理

      >值的方式,基于偏移的分页随着页码的增加而变得效率降低。这是因为当您使用偏移量时,数据库仍然必须扫描所有记录,直至偏移值。他们只是被丢弃,在查询结果中没有返回。

      > offset这是一篇很棒的文章,可以更详细地解释这一点:https://use-the-index-luke.com/no-offset。

      因此,随着数据库中数据总数的增长和页数增加,基于偏移的分页的效率也降低了。在这些情况下,基于光标的分页的性能更高,尤其是在索引光标字段的情况下,因为先前的记录未读取。因此,如果您要针对大型数据集使用分页,您可能需要选择光标分页而不是偏移分页。

      #是可能经常更改的数据集吗?

      如果请求之间的基础数据集更改,则基于偏移的分页可能会遇到问题。

      让我们来看看一个例子。

      是说我们数据库中有以下10个用户:

      >

      用户1

      用户2
      • 用户3
      • 用户4
      • >用户5
      • 用户6
      • 用户7
      • 用户8
      • >用户9
      • 用户10
      • 我们提出请求获取第一页(包含5个用户)并获取以下用户:>
      • 用户1

      用户2

        用户3
      • 用户4
      • >用户5
      • >当我们导航到第2页时,我们希望将用户6到10。但是,让我们想象,在加载第2页之前(当我们仍在查看第1页时),从数据库中删除了用户1。由于页面大小为5,因此获取下一页的查询看起来像:
      • >
      • 这意味着我们要跳过前5个记录并获取下一个5.
      这将导致包含以下用户的第2页:

      <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
      
      $users = User::query()->paginate();
      
      用户7

      用户8

      >用户9
      • 用户10
      • 正如我们所看到的,列表中缺少用户6。这是因为用户6现在是表中的第五个记录,因此它们实际上是在第一页上。
      • >基于光标的分页没有这个问题,因为我们没有跳过记录,我们只是根据光标获取下一组记录。让我们想象我们在上面的示例中使用了基于光标的分页。第2页的光标将是用户5的ID(我们假设为5),因为它是首页上的最后一个记录。因此,我们对第2页的查询可能看起来像这样:

        <!-- Syntax highlighted by torchlight.dev -->use App\Models\User;
        
        $users = User::query()->paginate();
        
        运行上述查询将按预期返回6至10的用户。

        >

        >这应该有望突出显示基于偏移的分页如何在读取基础数据,添加或删除的基础数据时如何成为问题。它变得不可预测,并可能导致意外的结果。

        >

        #您要构建API?

        >

        >重要的是要记住,您没有固定在应用程序中使用单一类型的分页。在某些地方,偏移分页可能更合适(也许是为了UI目的),而在其他地方,光标分页可能更有效(例如,使用大型数据集时)。因此,您可以根据用例中的应用程序混合和匹配分页方法。

        > 但是,如果您要构建API,我强烈建议您保持一致,并为所有端点使用单个分页方法。这将使开发人员更容易理解如何使用API​​并避免任何混乱。>

        >您不希望他们记住哪些端点使用偏移 - 流动以及哪些端点使用光标 -

        当然,这不是一个艰难而快速的规则。如果您确实需要在一个特定端点中使用其他分页方法,请继续。但是,只要确保在文档中清楚地表明它,以使开发人员更容易理解。

        #prefer视频?

        >

        >如果您更像是一个视觉学习者,则可能需要查看Aaron Francis的这个很棒的视频,该视频会更详细地解释基于偏移和基于Cursor的分页之间的区别:>

        #conclusion

        在本文中,我们研究了Laravel中不同类型的分页以及如何使用它们。我们还研究了他们的基础SQL查询以及如何确定在您的应用程序中使用的分页方法。希望您现在应该更有信心在Laravel应用程序中使用分页。

以上是Laravel的分页指南的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn