定义集合 #
一、集合配置文件 #
1.1 配置文件位置 #
内容集合的配置文件位于 src/content/config.ts:
typescript
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
// 集合配置
});
export const collections = {
blog,
};
1.2 集合类型 #
| 类型 | 说明 | 适用场景 |
|---|---|---|
content |
内容文件(Markdown/MDX) | 博客文章、文档 |
data |
数据文件(JSON/YAML) | 作者信息、配置 |
typescript
import { defineCollection } from 'astro:content';
const blog = defineCollection({
type: 'content', // Markdown/MDX 文件
});
const authors = defineCollection({
type: 'data', // JSON/YAML 文件
});
export const collections = { blog, authors };
二、Schema 定义 #
2.1 基本类型 #
typescript
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
schema: z.object({
// 字符串
title: z.string(),
description: z.string(),
// 数字
order: z.number(),
rating: z.number().min(1).max(5),
// 布尔值
draft: z.boolean(),
featured: z.boolean(),
// 日期
date: z.date(),
updated: z.date().optional(),
// 数组
tags: z.array(z.string()),
// 对象
author: z.object({
name: z.string(),
email: z.string().email(),
}),
}),
});
2.2 字符串验证 #
typescript
const blog = defineCollection({
schema: z.object({
// 基本字符串
title: z.string(),
// 非空字符串
title: z.string().min(1),
// 长度限制
title: z.string().min(1).max(100),
description: z.string().min(10).max(200),
// 正则验证
slug: z.string().regex(/^[a-z0-9-]+$/),
// 枚举值
status: z.enum(['draft', 'published', 'archived']),
// 邮箱
email: z.string().email(),
// URL
website: z.string().url(),
// 非空字符串(排除空格)
title: z.string().trim().min(1),
}),
});
2.3 数字验证 #
typescript
const product = defineCollection({
schema: z.object({
// 基本数字
price: z.number(),
// 整数
quantity: z.number().int(),
// 正数
price: z.number().positive(),
// 范围限制
rating: z.number().min(0).max(5),
discount: z.number().min(0).max(100),
// 默认值
quantity: z.number().default(0),
}),
});
2.4 日期处理 #
typescript
const blog = defineCollection({
schema: z.object({
// Date 对象
date: z.date(),
// 从字符串转换
date: z.coerce.date(),
// 从字符串或数字转换
date: z.coerce.date(),
// 可选日期
updated: z.coerce.date().optional(),
}),
});
2.5 数组验证 #
typescript
const blog = defineCollection({
schema: z.object({
// 字符串数组
tags: z.array(z.string()),
// 非空数组
tags: z.array(z.string()).min(1),
// 数组长度限制
tags: z.array(z.string()).min(1).max(10),
// 数字数组
ratings: z.array(z.number()),
// 对象数组
authors: z.array(z.object({
name: z.string(),
role: z.string(),
})),
// 默认值
tags: z.array(z.string()).default([]),
}),
});
三、可选和默认值 #
3.1 可选字段 #
typescript
const blog = defineCollection({
schema: z.object({
title: z.string(),
// 可选字段
subtitle: z.string().optional(),
image: z.string().optional(),
author: z.string().optional(),
// 可空字段
description: z.string().nullable(),
}),
});
3.2 默认值 #
typescript
const blog = defineCollection({
schema: z.object({
title: z.string(),
// 布尔默认值
draft: z.boolean().default(false),
featured: z.boolean().default(false),
toc: z.boolean().default(true),
// 字符串默认值
author: z.string().default('匿名'),
layout: z.string().default('blog'),
// 数组默认值
tags: z.array(z.string()).default([]),
categories: z.array(z.string()).default([]),
// 对象默认值
seo: z.object({
title: z.string().optional(),
description: z.string().optional(),
}).default({}),
}),
});
四、高级验证 #
4.1 条件验证 #
typescript
const blog = defineCollection({
schema: z.object({
title: z.string(),
image: z.string().optional(),
imageAlt: z.string().optional(),
}).refine(
data => !data.image || data.imageAlt,
{ message: '有图片时必须提供 imageAlt' }
),
});
4.2 自定义验证 #
typescript
const blog = defineCollection({
schema: z.object({
title: z.string(),
slug: z.string(),
date: z.coerce.date(),
}).refine(
data => data.slug === data.title.toLowerCase().replace(/\s+/g, '-'),
{ message: 'slug 必须是标题的小写连字符形式' }
),
});
4.3 转换数据 #
typescript
const blog = defineCollection({
schema: z.object({
title: z.string(),
// 转换为大写
category: z.string().transform(val => val.toUpperCase()),
// 转换并验证
tags: z.string().transform(val => val.split(',').map(t => t.trim())),
// 复杂转换
date: z.string().transform(val => new Date(val)),
}),
});
4.4 联合类型 #
typescript
const blog = defineCollection({
schema: z.object({
title: z.string(),
// 联合类型
status: z.union([
z.literal('draft'),
z.literal('published'),
z.literal('archived'),
]),
// 简写形式
status: z.enum(['draft', 'published', 'archived']),
// 可辨识联合
content: z.discriminatedUnion('type', [
z.object({ type: z.literal('text'), text: z.string() }),
z.object({ type: z.literal('image'), src: z.string(), alt: z.string() }),
]),
}),
});
五、图片处理 #
5.1 图片字段 #
typescript
const blog = defineCollection({
schema: ({ image }) => z.object({
title: z.string(),
// 图片字段
cover: image(),
// 图片带约束
cover: image().refine(img => img.width >= 1200, {
message: '封面图片宽度至少 1200px',
}),
// 可选图片
cover: image().optional(),
}),
});
5.2 使用图片 #
astro
---
import { getEntry } from 'astro:content';
import { Image } from 'astro:assets';
const post = await getEntry('blog', 'hello-world');
---
<article>
{post.data.cover && (
<Image
src={post.data.cover}
alt={post.data.title}
width={800}
/>
)}
</article>
六、关系定义 #
6.1 引用其他集合 #
typescript
const blog = defineCollection({
schema: z.object({
title: z.string(),
date: z.coerce.date(),
// 引用作者集合
author: z.string(),
}),
});
const authors = defineCollection({
type: 'data',
schema: z.object({
name: z.string(),
email: z.string().email(),
bio: z.string().optional(),
}),
});
export const collections = { blog, authors };
6.2 关联查询 #
astro
---
import { getEntry, getCollection } from 'astro:content';
const post = await getEntry('blog', 'hello-world');
const author = await getEntry('authors', post.data.author);
---
<article>
<h1>{post.data.title}</h1>
<p>作者: {author.data.name}</p>
</article>
七、完整示例 #
7.1 博客集合 #
typescript
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: ({ image }) => z.object({
title: z.string().min(1).max(100),
description: z.string().min(10).max(200),
date: z.coerce.date(),
updated: z.coerce.date().optional(),
author: z.string().default('anonymous'),
cover: image().optional(),
coverAlt: z.string().optional(),
tags: z.array(z.string()).default([]),
categories: z.array(z.string()).default([]),
draft: z.boolean().default(false),
featured: z.boolean().default(false),
toc: z.boolean().default(true),
comments: z.boolean().default(true),
}).refine(
data => !data.cover || data.coverAlt,
{ message: '有封面图时必须提供 coverAlt' }
),
});
const authors = defineCollection({
type: 'data',
schema: z.object({
name: z.string(),
avatar: z.string().optional(),
bio: z.string().optional(),
website: z.string().url().optional(),
twitter: z.string().optional(),
github: z.string().optional(),
}),
});
const docs = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
order: z.number().int().default(0),
section: z.string().optional(),
prev: z.string().optional(),
next: z.string().optional(),
}),
});
export const collections = {
blog,
authors,
docs,
};
7.2 内容文件示例 #
markdown
---
title: Astro
description: 介绍如何定义 Astro 内容集合,包括 Schema 配置、类型定义和高级验证。
date: 2024-01-15
author: zhangsan
cover: ./images/astro-guide.png
coverAlt: Astro 框架 Logo
tags:
- Astro
- 前端
- 静态站点
categories:
- 教程
featured: true
toc: true
---
# Astro 完全指南
Astro 是一款现代化的静态站点生成器...
八、最佳实践 #
8.1 Schema 组织 #
typescript
// src/content/schemas/common.ts
import { z } from 'astro:content';
export const seoSchema = z.object({
title: z.string().optional(),
description: z.string().optional(),
image: z.string().optional(),
});
export const authorSchema = z.object({
name: z.string(),
email: z.string().email().optional(),
url: z.string().url().optional(),
});
typescript
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
import { seoSchema, authorSchema } from './schemas/common';
const blog = defineCollection({
schema: z.object({
title: z.string(),
seo: seoSchema,
author: authorSchema,
}),
});
8.2 错误提示 #
typescript
const blog = defineCollection({
schema: z.object({
title: z.string({
required_error: '标题是必填项',
invalid_type_error: '标题必须是字符串',
}).min(1, '标题不能为空'),
date: z.coerce.date({
required_error: '日期是必填项',
invalid_type_error: '日期格式无效',
}),
}),
});
九、总结 #
定义集合核心要点:
text
┌─────────────────────────────────────────────────────┐
│ 定义集合要点 │
├─────────────────────────────────────────────────────┤
│ │
│ 📄 配置文件 src/content/config.ts │
│ │
│ 🔧 集合类型 content / data │
│ │
│ ✅ Schema 使用 Zod 定义验证规则 │
│ │
│ 📝 字段类型 string/number/boolean/date/array │
│ │
│ 🔗 关系 引用其他集合 │
│ │
│ 🖼️ 图片 image() 字段类型 │
│ │
└─────────────────────────────────────────────────────┘
下一步,让我们学习 查询数据,掌握内容查询 API!
最后更新:2026-03-28