Astro 架站筆記(五):巢狀分頁,製作出標籤列表
上一講提到文章列表,能夠透過動態路由 .../[page].astro
搭配傳入 getStaticPaths({ paginate })
中的 paginate()
函式來產生分頁,將所有的文章分成多頁。
但如果我們想製作能分頁的文章標籤(Tag)的列表呢?例如有 blue
、red
標籤,每個標籤下會有多篇文章,所以有類似 /tag/blue/1
、/tag/red/1
、/tag/red/2
這樣的 URLs,該如何使用 Astro 來開發呢?
這便會用到我們今天要聊聊的巢狀分頁。
新增文章 Tag
在建立巢狀分頁之前,我們先將文章的資訊加上 tags
這個屬性:
src/content.config.ts
1 | const blog = defineCollection({ |
然後建立幾篇文章,這裡先以 Markdown 或 MDX 為例,在其 frontmatter 中加入 tags: []
的資訊:
1 | --- |
如此一來,就能在後續的處理中撈出有出現的 tags
。
巢狀分頁
接著便進入今天的主題:巢狀分頁(Nested Pagination)。這是一種進階的分頁功能,當我們檔案出現如 src/pages/tag/[tag]/[page].astro
的巢狀動態路由(包含 [tag]
及其底下的 [page]
),就能做類似 /tag/blue/1
、/tag/red/1
、/tag/red/2
這樣針對不同 tag 的分頁,也因此稱之為巢狀分頁。
怎麼做呢?就繼續以部落格的標籤(tag)為例,來進行實作吧!
我們首先在 src/pages
下方建立 [tag]
資料,並在其之中建立 [page].astro
檔案。
取得所有 tags 及 tag 下的文章
就以上述新增的三篇部落格文章來說,這三篇文章分別對應到的 tags 是 a,b
、b,c
、c,d
,而我們希望獲得的是「有哪些標籤」及「每個標籤下有哪些文章」,這樣才能為每個標籤建立頁面並列出對應文章。
所以最終的內容會長成:
1 | const tagPostsMap = { |
如果有了這個 tagPostsMap
,就能夠透過 Object.keys(tagPostsMap)
來獲得 tags 陣列,也能知道 a
, b
, c
, d
標籤下的文章。
以下是在 src/pages/tag/[tag]/[page].astro
所實作的 getTagPostsMap
程式碼:
1 | import { getCollection } from 'astro:content'; |
其實僅僅是將所有文章撈出來後做簡單處理,將每篇文章的 tag 丟到 Map 中當 key,其 value 是文章的陣列。
巢狀分頁的 getStaticPaths()
在上一講提到的簡單分頁情境中,getStaticPaths({ paginate })
函式中,最後需要回傳一個 paginate()
呼叫後產生出的一組 Array of Object,Astro 會根據此 Array 產出多個頁面,將每個 Object 的頁碼塞入 Astro.params.page
,實際在產出 URL 的 [page]
便會被 Astro.params.page
替代。
而巢狀分頁會更複雜一些,我們首先從先前獲取的 tagPostsMap
出發,如下圖中最左邊的項目,這是一組 key-value pairs,key 就是 tag 名稱,而 value 則是文章(posts)的陣列。
我們需要對每個 tag 各自分頁,然後再將這些分頁的結果合併,最後由 Astro 產生靜態頁面。
例如下方的程式碼中,先對每個標籤(搭配其文章)呼叫 paginate()
,透過 flatMap()
讓最終回傳值是一個 Array of Object,每個 Object 就是一個包含 tag + posts 的頁面。
1 | export const getStaticPaths = async ({ paginate }) => { |
這樣一來,動態路由 /[tag]/[page]
中就會根據 tag
及 paginate()
產出的 page
來填入對應的數值,最終得到 6 頁的結果。