前面學習了內容集合與頁籤的製作,今天的主題練習透過整理集合抓取到的資料更進一步製作分類功能頁面。
隨著內容集合發布的文章越來越多,裡面可能會有許多相同性質的文章你會想要集合起來並替他們分類,並且自動根據類別自動創建頁面方便查閱。希望達成以下需求:
在集合的設定檔中定義好 category
資料,如無輸入時則預設給予 unsorted
字串。(該 post 集合記得要回傳)
const post = defineCollection({
schema: z.object({
isDraft: z.boolean().default(true),
category: z.string().default('unsorted'),
}),
});
集合定義好之後就可以開始在 content
當中撰寫 Markdown 或 MDX 資料了。
在 post/categories
中創建 index.astro
檔案,並索取 post
集合可用的文章內的 category
資料陣列,攤平裝入 Set 中(由於可能有多篇文章具備相同的類別,因此要消除重複的類別),最後再根據字母做分類,這樣便得到 categories
也就是當前該集合所有存在且不重複的分類名稱。
const publishedPosts = await getCollection('post', (post) => (import.meta.env.PROD ? !post.data.isDraft : true));
const categories = [...new Set(publishedPosts.map((post) => post.data.category).flat())]
.sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }),
);
接著只需要簡單的拿這筆資料在模板當中呈現即可。
{
categories.map((category) => (
<ul>
<li class="text-3xl">
<Card>
<a href={`/post/categories/${category}`}>{category}</a>
</Card>
</li>
</ul>
))
}
這裡需要使用到先前學到的動態路由與 getStaticPaths
方法。首先先創建一個動態路由檔案: pages/post/categories/[slug].astro
,並抓取當前該集合所有存在且不重複的分類名稱:
export async function getStaticPaths() {
/* 1. 抓取當前該集合所有存在且不重複的分類名稱,資料大致會長得像這樣:
[
'A-分類名稱', 'B-分類名稱', 'C-分類名稱',
]
*/
const publishedPosts = await getCollection('post', (post) => (import.meta.env.PROD ? !post.data.isDraft : true));
const categories = [...new Set(publishedPosts.map((post) => post.data.category).flat())]
/* 2. 最後製作 getStaticPaths 期望接收的資料
[
{ params: { slug: 'A-分類名稱' }, props: { publishedPosts: [Array] } },
{ params: { slug: 'B-分類名稱' }, props: { publishedPosts: [Array] } },
{ params: { slug: 'C-分類名稱' }, props: { publishedPosts: [Array] } },
]
*/
return categories.flatMap((category) => [{ params: { slug: category }, props: { publishedPosts } }]);
}
依照以上的操作順利透過 getStaticPaths
根據分類來創造分類頁面,除了創造頁面之外也替每個頁面傳入了 publishedPosts
的 Props,後續再過濾出跟這個 slug
相關的所有文章並依照時間分類。
const { slug } = Astro.params;
const { publishedPosts } = Astro.props;
const avaliableCurrentCategoryPosts = publishedPosts
.filter((post) => post.data.category === slug)
.sort((a, b) => b.data.publishDate.getTime() - a.data.publishDate.getTime());
在這個分類功能實作當中利用了動態路由與內容集合來產生文章分類頁面,可以在 GitHub 上觀賞我自己部落格的分類頁面作法。
(目前 iT 邦不支援 Astro 語法的高光 😅,因此歡迎到我的部落格閱讀本系列相關文章,正同步更新中!)