iT邦幫忙

2023 iThome 鐵人賽

DAY 16
0

https://ithelp.ithome.com.tw/upload/images/20230929/20141551Z3duP1mt7Q.jpg

前言

除了定義資料在元件中、在 srcimport 進來或者是 fetch 遠端資料之外有其他撰寫內容的方式嗎?有的!

什麼是內容集合 Content Collection?

內容集合於 2.0 版本推出,用於替網站的本地內容提供易於使用管理、自動化型別驗證的功能。如果你有大量文件需要注入網頁中便可以使用該項功能。

怎麼使用內容集合?

在介紹資料夾結構的章節中提到 src/content 是被保留的資料夾,其用途是用於存放內容集合相關的文件與設定,此外不能用做其他用途。首先可以創造一個條目資料夾,並且在裡面存放與該條目相關的文件,文件可以是 Markdown 或 MDX 甚至是 YAML 或 JSON:

src/content/
├── newsletter/
│   ├── week-1.md
│   └── week-2.md
├── blog/
│   ├── post-1.md
│   └── post-2.md
└── authors/
    ├── grace-hopper.json
    └── alan-turing.json

當創建好條目與其內容文件之後就可以透過 Astro 提供的 API 查詢。

什麼是 .astro 資料夾?

在使用內容集合時會發現 Astro 會為內容集合的設定自動生成相關的檔案,這些檔案會被放置在 .astro 資料夾中,不需要做任何的設定或修改,只要執行 astro devastro build 就會自動生成,也可以手動執行 astro sync 來生成。如果你有使用 Git 管理專案,建議將該資料夾給寫入 .gitignore 設定當中,避免被記錄下來。

定義集合

內容集合的設定是可選的,增加額外的集合設定將會更好的幫助 Astro 驗證資料的型別。要定義集合就需要創建 src/content/config.ts 文件(也可以是 .js.mjs),基本內容如下:

// 1. 導入 `astro:content` 提供的工具函式
import { defineCollection } from 'astro:content';
// 2. 定義集合
const blogCollection = defineCollection({ /* ... */ });
// 3. 輸出一個 `collections` 物件用於註冊集合,名稱應與條目資料夾相同
export const collections = {
  'blog': blogCollection,
};

透過定義集合型別可以強制集合內資料的準確與一致性,當有違背規則的情況 Astro 將會提供錯誤與建議,以下是一個集合物件的範例:

import { z, defineCollection } from 'astro:content';

defineCollection({
  type: 'content', // v2.5.0 版本新增,註明資料種類是 Markdown 還是像 JSON 或 YAML 的格式 (content / data)
  schema: z.object({
    title: z.string(),
    tags: z.array(z.string()),
    image: z.string().optional(),
  }),
});

當集合內的資料是 Markdown 時 typecontent,當是 JSON 或 YAML 時則是 dataschema 的設置可以參考 Zod 文件,Astro 使用 Zod 來為資料做檢核。

定義多個集合

可以創造多個集合之後再放入 collections 物件中。

const blogCollection = defineCollection({
  type: 'content',
  schema: z.object({ /* ... */ })
});
const newsletter = defineCollection({
  type: 'content',
  schema: z.object({ /* ... */ })
});
const authors = defineCollection({
  type: 'data',
  schema: z.object({ /* ... */ })
});

export const collections = {
  'blog': blogCollection,
  'newsletter': newsletter,
  'authors': authors,
};

查詢集合

Astro 提供兩個函式用於查詢一個或多個內容集合,分別是:getCollectiongetEntry

import { getCollection, getEntry } from 'astro:content';

// 獲取所有內容集合
// 需要集合的名稱作為參數
// 舉例來說: `src/content/blog/**`
const allBlogPosts = await getCollection('blog');

// 獲取單個條目從集合之中
// 需要集合的名稱以及條目 `slug` (內容集合)或 `id`(資料集合)
const graceHopperProfile = await getEntry('authors', 'grace-hopper');

篩選集合

getCollection 接受一個「過濾用」的回呼函式,用於過濾搜尋內容,像以下的案例:「當在 Production 環境時,如果該筆項目 draft 非為 true才顯示,在非 Production 則顯示一切資料」

import { getCollection } from 'astro:content';
const blogEntries = await getCollection('blog', ({ data }) => {
  return import.meta.env.PROD ? data.draft !== true : true;
});

顯示集合內容

透過 map 來遍歷並回傳每個項目的 Markup,我們能將撈取到的資料製作成一個清單並呈現到頁面當中。

---
import { getCollection } from 'astro:content';
const blogEntries = await getCollection('blog');
---
<ul>
  {blogEntries.map(blogPostEntry => (
    <li>
      <a href={`/my-blog-url/${blogPostEntry.slug}`}>{blogPostEntry.data.title}</a>
      <time datetime={blogPostEntry.data.publishedDate.toISOString()}>
        {blogPostEntry.data.publishedDate.toDateString()}
      </time>
    </li>
  ))}
</ul>

運用集合內容產生 SSG Route

一樣透過 getStaticPaths 這個方法,不過這次使用的資料不像之前一樣是寫死在元件內的,而是透過集合內容的資料來建立。

---
// 文件位置:src/pages/posts/[...slug].astro
import { getCollection } from 'astro:content';

export async function getStaticPaths() {
  // 1. 抓取 blog 集合
  const blogEntries = await getCollection('blog');
	// 2. 回傳個別的 Route 名稱與 Props 用於產生 Route
  return blogEntries.map(entry => ({
    params:{ slug: entry.slug }, props: { entry },
  }));
}
// 3. 再透過解構 Props 得到個別集合項目中的內容並顯示出來
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<h1>{entry.data.title}</h1>
<Content />

總結

最後會建議實際動手練習,如果過程中有問題可以參考看看我的範例

  • 使用 Astro 提供的 defineCollection 來創建自己理想的集合並定義其資料型態
  • content 資料夾中撰寫建立相關檔案
  • 使用 getCollection 抓取並顯示在頁面當中
  • 使用 getCollection 生成 Route

延伸閱讀

(目前 iT 邦不支援 Astro 語法的高光 😅,因此歡迎到我的部落格閱讀本系列相關文章,正同步更新中!)
Content Collections - Astro DOCS


上一篇
Day15 - 基礎布局
下一篇
Day17 - 實作頁籤
系列文
網頁開發沒有這麼簡單過!實際案例帶你上手 Astro.js30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言