乐闻世界logo
搜索文章和话题

什么是 Astro 的内容集合(Content Collections)?如何使用它来管理博客文章或文档?

2月21日 16:14

Astro 的内容集合(Content Collections)是一个强大的功能,用于管理结构化内容,如博客文章、文档、产品目录等。它提供了类型安全、性能优化和开发体验提升。

核心概念:

内容集合允许你在 src/content 目录下组织内容,并通过类型安全的 API 访问这些内容。

设置内容集合:

  1. 创建集合配置

    typescript
    // src/content/config.ts import { defineCollection, z } from 'astro:content'; const blog = defineCollection({ type: 'content', // 使用 Markdown/MDX schema: z.object({ title: z.string(), description: z.string(), publishDate: z.coerce.date(), tags: z.array(z.string()), image: z.string().optional(), }), }); const products = defineCollection({ type: 'data', // 使用 JSON/YAML schema: z.object({ name: z.string(), price: z.number(), category: z.string(), }), }); export const collections = { blog, products };
  2. 创建内容文件

    markdown
    <!-- src/content/blog/my-first-post.md --> --- title: "我的第一篇文章" description: "这是文章描述" publishDate: 2024-01-15 tags: ["astro", "tutorial"] image: "/images/post-1.jpg" --- 这是文章的正文内容...
    json
    // src/content/products/product-1.json { "name": "产品 1", "price": 99.99, "category": "电子" }

查询内容集合:

astro
--- import { getCollection } from 'astro:content'; // 获取所有博客文章 const allPosts = await getCollection('blog'); // 按日期排序 const posts = allPosts .filter(post => post.data.publishDate <= new Date()) .sort((a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf()); // 获取特定标签的文章 const astroPosts = await getCollection('blog', ({ data }) => { return data.tags.includes('astro'); }); --- <h1>博客文章</h1> {posts.map(post => ( <article> <h2>{post.data.title}</h2> <p>{post.data.description}</p> <time>{post.data.publishDate.toLocaleDateString()}</time> <a href={`/blog/${post.slug}`}>阅读更多</a> </article> ))}

获取单个条目:

astro
--- import { getEntry } from 'astro:content'; import type { CollectionEntry } from 'astro:content'; // 通过 slug 获取单个条目 const post = await getEntry('blog', 'my-first-post'); // 或者从 params 获取 const { slug } = Astro.params; const post = await getEntry('blog', slug); if (!post) { return Astro.redirect('/404'); } const { Content } = await post.render(); --- <h1>{post.data.title}</h1> <p>{post.data.description}</p> <Content />

动态路由与内容集合:

astro
--- // 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.slug }, props: { post }, })); } const { post } = Astro.props; const { Content } = await post.render(); --- <h1>{post.data.title}</h1> <Content />

使用 MDX:

markdown
--- title: "使用 MDX 的文章" description: "支持 JSX 的 Markdown" publishDate: 2024-01-20 tags: ["mdx", "astro"] --- import { Counter } from '../../components/Counter.jsx'; 这是普通的 Markdown 内容。 <Counter /> 你可以在这里使用任何组件!

内容集合的优势:

  1. 类型安全

    • 使用 Zod schema 定义内容结构
    • TypeScript 自动推断类型
    • 编译时验证
  2. 性能优化

    • 构建时处理内容
    • 自动生成路由
    • 避免运行时解析
  3. 开发体验

    • IDE 自动完成
    • 类型检查
    • 错误提示
  4. 灵活性

    • 支持 Markdown、MDX、JSON、YAML
    • 自定义 schema
    • 前置数据处理

高级用法:

  1. 嵌套目录

    shell
    src/content/ ├── blog/ │ ├── 2024/ │ │ ├── january/ │ │ │ └── post.md │ │ └── february/ │ │ └── post.md │ └── 2023/ │ └── post.md └── docs/ └── guide.md
  2. 自定义渲染器

    typescript
    // src/content/config.ts import { defineCollection, z } from 'astro:content'; const blog = defineCollection({ type: 'content', schema: z.object({ title: z.string(), }), // 自定义渲染器 render: async ({ entry }) => { // 自定义渲染逻辑 return entry.render(); }, });
  3. 内容转换

    typescript
    // src/content/config.ts const blog = defineCollection({ type: 'content', schema: z.object({ title: z.string(), date: z.coerce.date(), }), transform: async (data, id) => { // 转换数据 return { ...data, slug: id.replace('.md', ''), }; }, });

最佳实践:

  1. 使用 Zod schema 定义清晰的内容结构
  2. 为不同的内容类型创建单独的集合
  3. 利用 TypeScript 获得类型安全
  4. 使用 getStaticPaths 生成动态路由
  5. 在构建时处理所有内容,避免运行时开销

内容集合是 Astro 处理结构化内容的最佳方式,特别适合博客、文档、产品目录等内容驱动的网站。

标签:Astro