在現代的 Web 應用中,使用者體驗是至關重要的。很多時候,網頁載入速度直接影響到使用者的滿意度,特別是當資料量龐大時。GraphQL 是一種允許客戶端明確請求所需資料的查詢語言,透過分頁查詢,我們可以進一步優化使用者體驗,避免一次載入過多不必要的資料。
本次實戰演練中,我們將探討如何在 Vue 框架中運用 GraphQL 的分頁查詢功能,進而優化文章列表頁面的載入速度。而不是一次性讀取全部的一百篇文章,我們會使用分頁技巧,每次只載入部分文章,從而加速頁面的載入並提供更流暢的滾動體驗。
Day15 開始前分支:feat/day_14/implement_blog_detail_view_using_variables
Day15 進度完成分支:feat/day_15/enhance_blog_list_view_by_pagination
分頁查詢泛指一種只取出部分資料的技術。當我們面對大量的資料時,一次性地取出所有資料是不實際的,也可能會造成系統的過度負擔。這時,分頁查詢就派上用場,它允許我們基於某些條件(如資料的順序、特定範圍、或用戶的請求)來取出部分資料。
舉一個常見的例子:當使用者在一個電商平台上搜尋商品時,結果可能有上千個商品,但螢幕上只會顯示前 20 筆。當使用者觸發下一個分頁顯示條件時,更多的商品才會被加載顯示。這就是分頁查詢的實際應用。
在 GraphQL 的語境中,分頁查詢允許我們以更靈活和高效的方式取得部分資料集。傳統的 RESTful API 中,分頁通常是透過 URL 參數來完成,而在 GraphQL 中,我們可以進一步定制查詢,取得確切所需的資料。
GraphQL 提供了兩種主要的分頁方法:
Offset-based Pagination: 這是最基本的分頁方法,通常使用 limit
和 offset
參數來確定要取得的資料範圍。
Cursor-based Pagination: 較為先進,且被許多大型應用所採用。它使用特定的 cursor
來標記資料的起始和結束位置,通常結合 first
或 last
參數來取得資料。
稍後,本文將會使用基礎的 Offset-based Pagination 作為分頁查詢的示範。
總之,GraphQL 的分頁查詢提供了一種更加高效、靈活和使用者友善的方法來獲取資料,確保應用在各種情境下都能夠提供最佳的使用者體驗。
先前我們選用的 Fake Online GraphQL API — GraphQLZero — 在其文件中明確表示支援分頁功能。
因此,我們只需根據該文件指引修改 GraphQL 查詢,即可輕鬆開始實作分頁查詢功能。
在 Play Ground 的測試結果中,正如我們所指定的,系統只回傳了前五筆資料。
Offset-based Pagination 的計算方法:
Offset-based Pagination 主要使用 limit
和 offset
這兩個參數來定義資料的範圍。
簡單來說,offset
是告訴系統從哪條記錄開始,而 limit
是指定要取得多少筆資料。
假設每頁要顯示 10 筆資料,那麼 limit
就設為 10。而 offset
的值則會根據頁碼而變,計算公式為:(頁碼 - 1) * 每頁資料量
舉例:
如果想要取得第一頁的資料:
limit
= 10offset
= (1 - 1) * 10 = 0如果想要取得第三頁的資料:
limit
= 10offset
= (3 - 1) * 10 = 20通過這種方式,系統知道第三頁的資料是從第 21 筆開始,並取得 10 筆資料。
完整程式碼範例請參考:feat/day_15/enhance_blog_list_view_by_pagination
in src/views/BlogListView.vue
gqlGetPostsPerPage
<script setup lang="ts">
// ...
// 設定起始頁面為第一頁面
const defaultPage = 1
// 當前頁碼
const currentPage = ref(defaultPage)
// 一頁幾筆資料
const limit = ref(8)
const { result, loading, error } = useQuery(gqlGetPostsPerPage, () => ({
options: {
paginate: {
page: currentPage.value,
limit: limit.value,
},
},
}))
const posts = computed(() => (result.value?.posts?.data ?? []) as Post[])
const totalCount = computed(() => result.value?.posts?.meta?.totalCount ?? 0)
</script>
<template>
// ...
</template>
<template>
<!-- ... -->
<Pagination v-slot="{ page }" :total="totalCount" :items-per-page="limit" :sibling-count="1" show-edges :default-page="defaultPage" class="mt-8">
<PaginationList v-slot="{ items }" class="flex items-center justify-center gap-1">
<PaginationFirst />
<PaginationPrev />
<template v-for="(item, index) in items">
<PaginationListItem v-if="item.type === 'page'" :key="index" :value="item.value" as-child>
<Button class="w-10 h-10 p-0" :variant="item.value === page ? 'default' : 'outline'" @click.prevent="currentPage = item.value">
{{ item.value }}
</Button>
</PaginationListItem>
<PaginationEllipsis v-else :key="item.type" :index="index" />
</template>
<PaginationNext />
<PaginationLast />
</PaginationList>
</Pagination>
</template>
由於之前的重構並採取了模組化的策略,即使我們從撈取大量文章切換到分頁查詢,我們也只需進行如此簡單的修改即可完成分頁功能。
在本次示範中,我們採用了最基礎的分頁實作方式。
這種方法在初級應用上非常方便和直觀,但在資料量龐大的情況下可能會有效能問題。
所以,實務上其實更傾向於使用 Cursor-based Pagination 結合**無限滾動 (infinite scroll) **的方法。這樣不僅可以提供更優質的使用者體驗,也使內容更新更為即時。
使用分頁查詢前
使用分頁查詢後
根據圖片的結果,我們可以觀察到,伺服器的回應時間已經縮短了 1.48254 秒,這意味著我們成功地減少了大約 70% 的等待時間!
透過這次的實戰演練,我們已經學習了如何在 Vue 應用中運用 GraphQL 的分頁查詢技巧,有效地減少不必要的資料載入,提高頁面的載入速度,並且提供更好的使用者體驗。
分頁查詢不僅限於文章列表,同樣的技術也可以應用在其他需要大量資料的場景,如商品列表、用戶列表等。隨著資料量的增加,適時地優化應用將更加重要。
明日預告:探索 GraphQL 條件查詢
準備好深入 GraphQL 的另一項強大功能了嗎?明天,我們將一同探討 GraphQL 的條件查詢,可以更靈活地取得所需要的資料。不只是簡單的查詢,更是按照特定條件來篩選和排序!不要錯過,我們明天見!