iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0
Modern Web

LV的全端開發體驗系列 第 24

Day24 前後端分離後的分頁 - Laravel Paginate & Vue

  • 分享至 

  • xImage
  •  

分頁一直是個有點難度但做法又大同小異的議題,Laravel 本身提供的Paginate除了針對自己的Blade很方便之外,對於前端來說也是滿友善的,如果有特別需求,Laravel也提供了可以自訂的方法;

今天我只想先確認一下原本Laravel提供的分頁方式,是否可以直接給前端使用,至於進階的自訂做法,可能等之後有明確需求時再來進行。

因為 Paginate 是基於 Model 的一個方法,所以要從 Repository 中來修改取出的資料方式:
app\Repositories\SubjectRepository.php

function subjectsInBank($bank_id)
{
   return $this->subject->where('bank_id',$bank_id)->get();
}

改成

function subjectsInBank($bank_id)
{
    //資料筆數是暫時填的,未來會做成可以參數傳入
   return $this->subject->where('bank_id',$bank_id)->paginate(10);
}

透過vue的瀏灠器工具可以看到 Paginate 傳到前端的整包物件內容,資料本身在 data 這個屬性,分頁項目在 links 中,其它則是分頁相關的各種資訊:

修改一下前端原本接收資料的方式:

resources\js\Pages\Backstage\Subjects.vue

.....略

  //題目資料改由subjects.data取得
  <div v-for="subject in subjects.data"
        :key="subject.id"
        class="w-full border rounded-xl flex py-2 px-4 bg-green-400 justify-between">
    <div>{{ subject.seq }}. {{ subject.subject }}</div>
    <div>
      <Link :href="route('subject.edit',subject.id)" method="get" as="button">編輯</Link>
      /
      <Link :href="route('subject.destroy',subject.id)" method="delete" as="button">刪除</Link>
    </div>
  </div>

.....略

接著在下方增加分頁的資訊:
resources\js\Pages\Backstage\Subjects.vue

.....略

<div v-if="subjects.links.length > 3">
    <div class="flex flex-wrap -mb-1">
        <template v-for="(page, idx) in subjects.links" :key="idx">
            <div v-if="page.url === null" 
                 class="mr-1 mb-1 px-4 py-3 text-sm leading-4 text-gray-400 border rounded"
                 v-html="page.label" />
            <Link v-else
                class="mr-1 mb-1 px-4 py-3 text-sm leading-4 border rounded hover:bg-white focus:border-indigo-500 focus:text-indigo-500"
                :class="{ 'bg-blue-700 text-white': page.active }" 
                :href="page.url" 
                v-html="page.label" />
        </template>
    </div>
</div>

這樣就可以快速的完成一個分頁的功能,並且搭配 InertiaLink 組件使用ajax的方式來載入各頁面。
當然,我們不會只有這個頁面使用到這個功能,所以我們可以把這個下方分頁連結做成一個組件,讓其它有需要的地方可以更簡單的使用:
resources\js\QuizComponents\Paginator.vue

<script setup>
import {Link } from "@inertiajs/inertia-vue3";
defineProps({links:Array})
</script>
<template>
<div v-if="links.length > 3" class="my-4">
    <div class="flex flex-wrap ml-[1px] -mb-1 justify-center">
        <template v-for="(page, idx) in links" :key="idx">
            <!--因為分頁的字串中帶有特殊符號,所以透過v-html來轉義-->
            <div v-if="page.url === null" 
                 class="mb-1 px-4 py-3 text-sm leading-4 text-gray-400 border rounded"
                 v-html="page.label" />
            <Link v-else
                class="-ml-[1px] mb-1 px-4 py-3 text-sm leading-4 border rounded hover:bg-slate-200  focus:border-indigo-500 focus:text-indigo-500"
                :class="{'bg-blue-700 text-white hover:bg-blue-500': page.active}"
                :href="page.url" 
                  v-html="page.label" />
        </template>
    </div>
</div>
</template>

在需要分頁的頁面可以簡單的引入並帶入參數:
resources\js\Pages\Backstage\Subjects.vue

.....略

<Paginator :links="subjects.links" />

.....略

如果資料總筆數不多的話,另外一種做法是把資料全部丟到前端,在前端直接做分頁(可以使用datatable之類的套件
),但資料量大的時候,光等資料下載完畢就是一個問題,以我的這個應用來說,最後題目都是以千起算的筆數,所以最好的做法還是由後端來提供適量的分頁資料就好。


上一篇
Day23 再談前端組件設計-Button Component
下一篇
Day25 使用者的後台觀看權限 - Route & Middleware
系列文
LV的全端開發體驗30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言