Content Collections
Content Collections 是 Astro 内置的内容管理系统,用于在 src/content/ 目录下组织和管理结构化内容。每个集合通过配置文件定义 schema,提供类型安全和自动校验。
以本文档站为例,src/content.config.ts 的配置:
// src/content.config.ts
import { defineCollection, z } from 'astro:content'
import { glob } from 'astro/loaders'
const docs = defineCollection({
loader: glob({ pattern: '**/*.md', base: 'src/content/docs' }),
schema: z.object({
title: z.string(),
description: z.string().optional(),
}),
})
export const collections = { docs }
关键配置项:
loader— 指定内容来源,glob加载器可以扫描文件系统schema— 用 Zod 定义 frontmatter 字段的类型,支持z.string()、z.date()、z.enum()等
在页面中查询内容集合:
---
import { getCollection } from 'astro:content'
// 获取 docs 集合中的所有条目
const allDocs = await getCollection('docs')
// 按 slug 排序
const sorted = allDocs.sort((a, b) =>
a.id.localeCompare(b.id)
)
---
<h1>文档列表</h1>
<ul>
{sorted.map(doc => (
<li>
<a href={`/docs/${doc.id}`}>{doc.data.title}</a>
<p>{doc.data.description}</p>
</li>
))}
</ul>
getCollection() 返回的条目包含 id、data(经过校验的 frontmatter)、body(原始内容)等属性。
Markdown / MDX
Astro 对 .md 和 .mdx 文件提供一等支持。Markdown 文件通过 YAML frontmatter 定义元数据:
---
title: Hello World
description: 第一篇博客
pubDate: 2025-06-01
tags: [astro, guide]
layout: ../../layouts/BlogLayout.astro
---
MDX 在 Markdown 基础上允许在内容中直接使用 Astro 或框架组件:
---
title: MDX 示例
layout: ../../layouts/BlogLayout.astro
---
这是一个 MDX 文章。可以在内容中插入组件:
import Counter from '../../components/Counter.astro'
## 计数器示例
<Counter initialValue={10} />
要在项目中使用 MDX,需要安装 @astrojs/mdx 集成:
bun add @astrojs/mdx
然后在 astro.config.mjs 中添加:
import { defineConfig } from 'astro/config'
import mdx from '@astrojs/mdx'
export default defineConfig({
integrations: [mdx()],
})
动态路由
动态路由允许根据参数生成多个页面。文件名用方括号 [param] 表示动态段。
目录结构示例:
src/pages/
└── blog/
├── [slug].astro → /blog/:slug
└── tags/[tag].astro → /blog/tags/:tag
在页面中使用 getStaticPaths() 声明所有可能的路径:
---
// src/pages/blog/[slug].astro
import { getCollection } from 'astro:content'
export async function getStaticPaths() {
const posts = await getCollection('blog')
return posts.map(post => ({
params: { slug: post.id },
props: { post },
}))
}
const { post } = Astro.props
const { Content } = await post.render()
---
<h1>{post.data.title}</h1>
<Content />
getStaticPaths() 返回一个数组,每项包含 params(URL 参数)和 props(传入组件的属性)。Astro 在构建时会根据这个数组生成所有页面。
分页
Astro 内置分页功能,通过 paginate() 函数实现:
---
// src/pages/blog/[...page].astro
import { getCollection } from 'astro:content'
import Pagination from '../../components/Pagination.astro'
export async function getStaticPaths({ paginate }) {
const posts = await getCollection('blog')
const sorted = posts.sort((a, b) =>
b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
)
return paginate(sorted, { pageSize: 10 })
}
const { page } = Astro.props
---
<h1>博客列表 - 第 {page.currentPage} 页</h1>
<ul>
{page.data.map(post => (
<li>
<a href={`/blog/${post.id}`}>{post.data.title}</a>
<time>{post.data.pubDate.toLocaleDateString('zh-CN')}</time>
</li>
))}
</ul>
<Pagination page={page} />
page 对象包含以下属性:
| 属性 | 说明 |
|---|---|
page.data | 当前页的条目数组 |
page.currentPage | 当前页码 |
page.lastPage | 总页数 |
page.url.next | 下一页 URL(无下一页时为 undefined) |
page.url.prev | 上一页 URL |
RSS 生成
使用 @astrojs/rss 包可以快速生成 RSS Feed:
bun add @astrojs/rss
在 src/pages/rss.xml.ts 中创建 RSS 端点:
import rss from '@astrojs/rss'
import { getCollection } from 'astro:content'
export async function GET(context) {
const posts = await getCollection('blog')
const sorted = posts.sort((a, b) =>
b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
)
return rss({
title: '我的博客',
description: '技术文章与心得分享',
site: context.site,
items: sorted.map(post => ({
title: post.data.title,
pubDate: post.data.pubDate,
description: post.data.description,
link: `/blog/${post.id}/`,
})),
})
}
访问 /rss.xml 即可获取 RSS Feed。需要确保 astro.config.mjs 中配置了 site 字段。