Skip to content

内容集合

Added in: astro@2.0.0

内容集合是管理任何 Astro 项目中的内容集的最佳方式。集合有助于组织和查询你的文档,在编辑器中启用 Intellisense 和类型检查,并为你的所有内容提供自动 TypeScript 类型安全。Astro v5.0 引入了用于定义和查询内容集合的内容层 API。这个高性能、可扩展的 API 为你的本地集合提供了内置的内容加载器。对于远程内容,你可以使用第三方和社区构建的加载器,也可以创建自己的自定义加载器并从任何来源提取数据。

¥Content collections are the best way to manage sets of content in any Astro project. Collections help to organize and query your documents, enable Intellisense and type checking in your editor, and provide automatic TypeScript type-safety for all of your content. Astro v5.0 introduced the Content Layer API for defining and querying content collections. This performant, scalable API provides built-in content loaders for your local collections. For remote content, you can use third-party and community-built loaders or create your own custom loader and pull in your data from any source.

¥What are Content Collections?

你可以从结构相似的一组数据中定义一个集合。这可以是博客文章的目录、产品项目的 JSON 文件或代表相同形状的多个项目的任何数据。

¥You can define a collection from a set of data that is structurally similar. This can be a directory of blog posts, a JSON file of product items, or any data that represents multiple items of the same shape.

存储在你的项目或文件系统中的本地集合可以包含 Markdown、MDX、Markdoc 或 JSON 文件的条目:

¥Collections stored locally in your project or on your filesystem can have entries of Markdown, MDX, Markdoc, or JSON files:

  • Directorysrc/
  • Directorynewsletter/ the “newsletter” collection
    • week-1.md a collection entry
    • week-2.md a collection entry
    • week-3.md a collection entry
  • Directoryauthors/ the “author” collection
    • authors.json a single file containing all collection entries

使用适当的集合加载器,你可以从任何外部来源(例如 CMS、数据库或无头支付系统)获取远程数据。

¥With an appropriate collection loader, you can fetch remote data from any external source, such as a CMS, database, or headless payment system.

集合的 TypeScript 配置

标题部分 集合的 TypeScript 配置

¥TypeScript configuration for collections

内容集合依靠 TypeScript 在你的编辑器中提供 Zod 验证、Intellisense 和类型检查。如果你没有扩展 Astro 的 strictstrictest TypeScript 设置之一,则需要确保在 tsconfig.json 中设置了以下 compilerOptions

¥Content collections rely on TypeScript to provide Zod validation, Intellisense and type checking in your editor. If you are not extending one of Astro’s strict or strictest TypeScript settings, you will need to ensure the following compilerOptions are set in your tsconfig.json:

tsconfig.json
{
// Included with "astro/tsconfigs/strict" or "astro/tsconfigs/strictest"
"extends": "astro/tsconfigs/base",
"compilerOptions": {
"strictNullChecks": true, // add if using `base` template
"allowJs": true // required, and included with all Astro templates
}
}

¥Defining Collections

单个集合使用 defineCollection() 进行配置:

¥Individual collections use defineCollection() to configure:

  • 数据源的 loader(必需)

  • 类型安全的 schema(可选,但强烈推荐!)

¥The collection config file

要定义集合,你必须在项目中创建一个 src/content.config.ts 文件(.js.mjs 扩展也受支持)。这是一个特殊文件,Astro 将使用它根据以下结构配置你的内容集合:

¥To define collections, you must create a src/content.config.ts file in your project (.js and .mjs extensions are also supported.) This is a special file that Astro will use to configure your content collections based on the following structure:

src/content.config.ts
// 1. Import utilities from `astro:content`
import { defineCollection, z } from 'astro:content';
// 2. Import loader(s)
import { glob, file } from 'astro/loaders';
// 3. Define your collection(s)
const blog = defineCollection({ /* ... */ });
const dogs = defineCollection({ /* ... */ });
// 4. Export a single `collections` object to register your collection(s)
export const collections = { blog, dogs };

¥Defining the collection loader

内容层 API 允许你获取内容(无论是存储在项目本地还是远程),并使用 loader 属性检索数据。

¥The Content Layer API allows you to fetch your content (whether stored locally in your project or remotely) and uses a loader property to retrieve your data.

¥Built-in loaders

Astro 提供了两个内置加载器函数(glob()file())用于获取本地内容,以及访问 API 以构建你自己的加载器并获取远程数据。

¥Astro provides two built-in loader functions (glob() and file()) for fetching your local content, as well as access to the API to construct your own loader and fetch remote data.

glob() 加载器从文件系统上任何位置的 Markdown、MDX、Markdoc 或 JSON 文件的目录中创建条目。它接受要匹配的条目文件的 pattern,以及文件所在位置的 base 文件路径。每个条目的 id 都将从其文件名自动生成。当每个条目有一个文件时使用此加载器。

¥The glob() loader creates entries from directories of Markdown, MDX, Markdoc, or JSON files from anywhere on the filesystem. It accepts a pattern of entry files to match, and a base file path of where your files are located. Each entry’s id will be automatically generated from its file name. Use this loader when you have one file per entry.

file() 加载器从单个本地文件创建多个条目。文件中的每个条目都必须具有唯一的 id 键属性。它接受文件的 base 文件路径,并可选地接受无法自动解析的数据文件的 parser 功能。当数据文件可以解析为对象数组时使用此加载器。

¥The file() loader creates multiple entries from a single local file. Each entry in the file must have a unique id key property. It accepts a base file path to your file and optionally a parser function for data files it cannot parse automatically. Use this loader when your data file can be parsed as an array of objects.

src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob, file } from 'astro/loaders'; // Not available with legacy API
const blog = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
schema: /* ... */
});
const dogs = defineCollection({
loader: file("src/data/dogs.json"),
schema: /* ... */
}),
});
const probes = defineCollection({
// `loader` can accept an array of multiple patterns as well as string patterns
// Load all markdown files in the space-probes directory, except for those that start with "voyager-"
loader: glob({ pattern: ['*.md', '!voyager-*'], base: 'src/data/space-probes' }),
schema: z.object({
name: z.string(),
type: z.enum(['Space Probe', 'Mars Rover', 'Comet Lander']),
launch_date: z.date(),
status: z.enum(['Active', 'Inactive', 'Decommissioned']),
destination: z.string(),
operator: z.string(),
notable_discoveries: z.array(z.string()),
}),
});
export const collections = { blog, dogs, probes };

¥parser function

file() 加载器接受定义 parser 函数的第二个参数。这允许你指定自定义解析器(例如 toml.parsecsv-parse)以从文件的内容创建集合。

¥The file() loader accepts a second argument that defines a parser function. This allows you to specify a custom parser (e.g. toml.parse or csv-parse) to create a collection from a file’s contents.

file() 加载器将自动检测并解析 JSON 和 YAML 文件中的单个对象数组(基于其文件扩展名),除非你有 嵌套 JSON 文档,否则无需 parser。要使用其他文件(例如 .toml.csv),你需要创建一个解析器函数。

¥The file() loader will automatically detect and parse a single array of objects from JSON and YAML files (based on their file extension) with no need for a parser unless you have a nested JSON document. To use other files, such as .toml and .csv, you will need a to create a parser function.

以下示例使用 .toml 文件定义内容集合 dogs

¥The following example defines a content collection dogs using a .toml file:

src/data/dogs.toml
[[dogs]]
id = "..."
age = "..."
[[dogs]]
id = "..."
age = "..."

导入 TOML 的解析器后,你可以通过将文件路径和 parser 函数传递给 file() 加载器,将 dogs 集合加载到你的项目中。可以使用类似的过程从 .csv 文件定义 cats 集合:

¥After importing TOML’s parser, you can load the dogs collection into your project by passing both a file path and parser function to the file() loader. A similar process can be used to define a cats collection from a .csv file:

src/content.config.ts
import { defineCollection } from "astro:content";
import { file } from "astro/loaders";
import { parse as parseToml } from "toml";
import { parse as parseCsv } from "csv-parse/sync";
const dogs = defineCollection({
loader: file("src/data/dogs.toml", { parser: (text) => parseToml(text).dogs }),
schema: /* ... */
})
const cats = defineCollection({
loader: file("src/data/cats.csv", { parser: (text) => parseCsv(text, { columns: true, skipEmptyLines: true })})
});

¥Nested .json documents

parser 参数还允许你从嵌套的 JSON 文档加载单个集合。例如,此 JSON 文件包含多个集合:

¥The parser argument also allows you to load a single collection from a nested JSON document. For example, this JSON file contains multiple collections:

src/data/pets.json
{"dogs": [{}], "cats": [{}]}

你可以通过将自定义 parser 传递给每个集合的 file() 加载器来分离这些集合:

¥You can separate these collections by passing a custom parser to the file() loader for each collection:

src/content.config.ts
const dogs = defineCollection({
loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).dogs })
});
const cats = defineCollection({
loader: file("src/data/pets.json", { parser: (text) => JSON.parse(text).cats })
});

¥Building a custom loader

你可以构建自定义加载器以从任何数据源(例如 CMS、数据库或 API 端点)获取远程内容。

¥You can build a custom loader to fetch remote content from any data source, such as a CMS, a database, or an API endpoint.

使用加载器获取数据将自动从远程数据创建集合。这为你提供了本地集合的所有好处,例如集合特定的 API 助手(如 getCollection()render())用于查询和显示你的数据,以及架构验证。

¥Using a loader to fetch your data will automatically create a collection from your remote data. This gives you all the benefits of local collections, such as collection-specific API helpers such as getCollection() and render() to query and display your data, as well as schema validation.

¥Inline loaders

你可以在集合内内联定义加载器,将其作为返回条目数组的异步函数。

¥You can define a loader inline, inside your collection, as an async function that returns an array of entries.

这对于不需要手动控制数据加载和存储方式的加载器很有用。每当调用加载器时,它都会清除存储并重新加载所有条目。

¥This is useful for loaders that don’t need to manually control how the data is loaded and stored. Whenever the loader is called, it will clear the store and reload all the entries.

src/content.config.ts
const countries = defineCollection({
loader: async () => {
const response = await fetch("https://restcountries.com/v3.1/all");
const data = await response.json();
// Must return an array of entries with an id property, or an object with IDs as keys and entries as values
return data.map((country) => ({
id: country.cca3,
...country,
}));
},
schema: /* ... */
});

返回的条目存储在集合中,可以使用 getCollection()getEntry() 函数进行查询。

¥The returned entries are stored in the collection and can be queried using the getCollection() and getEntry() functions.

¥Loader objects

为了更好地控制加载过程,你可以使用内容加载器 API 创建加载器对象。例如,通过直接访问 load 方法,你可以创建一个加载器,允许条目逐步更新或仅在必要时清除存储。

¥For more control over the loading process, you can use the Content Loader API to create a loader object. For example, with access to the load method directly, you can create a loader that allows entries to be updated incrementally or clears the store only when necessary.

与创建 Astro 集成或 Vite 插件类似,你可以创建其他人可以在其项目中使用的 将你的加载器作为 NPM 包分发

¥Similar to creating an Astro integration or Vite plugin, you can distribute your loader as an NPM package that others can use in their projects.

See the full Content Loader API and examples of how to build your own loader.

¥Defining the collection schema

架构通过 Zod 验证强制集合内的前言或条目数据一致。模式保证当你需要引用或查询此数据时,它以可预测的形式存在。如果任何文件违反其集合架构,Astro 将提供有用的错误来通知你。

¥Schemas enforce consistent frontmatter or entry data within a collection through Zod validation. A schema guarantees that this data exists in a predictable form when you need to reference or query it. If any file violates its collection schema, Astro will provide a helpful error to let you know.

模式还为 Astro 的内容自动 TypeScript 类型提供支持。当你为集合定义架构时,Astro 将自动生成 TypeScript 接口并将其应用到其中。当你查询集合时,结果是完整的 TypeScript 支持,包括属性自动补齐和类型检查。

¥Schemas also power Astro’s automatic TypeScript typings for your content. When you define a schema for your collection, Astro will automatically generate and apply a TypeScript interface to it. The result is full TypeScript support when you query your collection, including property autocompletion and type-checking.

你的集合条目的每个前言或数据属性都必须使用 Zod 数据类型进行定义:

¥Every frontmatter or data property of your collection entries must be defined using a Zod data type:

src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob, file } from 'astro/loaders'; // Not available with legacy API
const blog = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
})
});
const dogs = defineCollection({
loader: file("src/data/dogs.json"),
schema: z.object({
id: z.string(),
breed: z.string(),
temperament: z.array(z.string()),
}),
});
export const collections = { blog, dogs };

使用 Zod 定义数据类型

标题部分 使用 Zod 定义数据类型

¥Defining datatypes with Zod

Astro 使用 佐德 来支持其内容模式。使用 Zod,Astro 能够验证集合中每个文件的数据,并在你从项目内部查询内容时提供自动 TypeScript 类型。

¥Astro uses Zod to power its content schemas. With Zod, Astro is able to validate every file’s data within a collection and provide automatic TypeScript types when you go to query content from inside your project.

要在 Astro 中使用 Zod,请从 "astro:content" 导入 z 实用程序。这是 Zod 库的重新导出,它支持 Zod 的所有功能。

¥To use Zod in Astro, import the z utility from "astro:content". This is a re-export of the Zod library, and it supports all of the features of Zod.

// Example: A cheatsheet of many common Zod datatypes
import { z, defineCollection } from 'astro:content';
defineCollection({
schema: z.object({
isDraft: z.boolean(),
title: z.string(),
sortOrder: z.number(),
image: z.object({
src: z.string(),
alt: z.string(),
}),
author: z.string().default('Anonymous'),
language: z.enum(['en', 'es']),
tags: z.array(z.string()),
footnote: z.string().optional(),
// In YAML, dates written without quotes around them are interpreted as Date objects
publishDate: z.date(), // e.g. 2024-09-17
// Transform a date string (e.g. "2022-07-08") to a Date object
updatedDate: z.string().transform((str) => new Date(str)),
authorContact: z.string().email(),
canonicalURL: z.string().url(),
})
})
See Zod’s README for complete documentation on how Zod works and what features are available.

¥Zod schema methods

所有 Zod 模式方法(例如 .parse().transform())都可用,但有一些限制。值得注意的是,不支持使用 image().refine() 对图片执行自定义验证检查。

¥All Zod schema methods (e.g. .parse(), .transform()) are available, with some limitations. Notably, performing custom validation checks on images using image().refine() is unsupported.

¥Defining collection references

集合条目还可以 “reference” 其他相关条目。

¥Collection entries can also “reference” other related entries.

使用 Collections API 中的 reference() 函数,你可以将集合架构中的属性定义为另一个集合中的条目。例如,你可以要求每个 space-shuttle 条目都包含一个 pilot 属性,该属性使用 pilot 集合自己的架构进行类型检查、自动补齐和验证。

¥With the reference() function from the Collections API, you can define a property in a collection schema as an entry from another collection. For example, you can require that every space-shuttle entry includes a pilot property which uses the pilot collection’s own schema for type checking, autocomplete, and validation.

一个常见的示例是引用以 JSON 形式存储的可重用作者个人资料或存储在同一集合中的相关帖子 URL 的博客文章:

¥A common example is a blog post that references reusable author profiles stored as JSON, or related post URLs stored in the same collection:

src/content.config.ts
import { defineCollection, reference, z } from 'astro:content';
const blog = defineCollection({
loader: glob({ pattern: '**/[^_]*.md', base: "./src/data/blog" }),
schema: z.object({
title: z.string(),
// Reference a single author from the `authors` collection by `id`
author: reference('authors'),
// Reference an array of related posts from the `blog` collection by `slug`
relatedPosts: z.array(reference('blog')),
})
});
const authors = defineCollection({
loader: glob({ pattern: '**/[^_]*.json', base: "./src/data/authors" }),
schema: z.object({
name: z.string(),
portfolio: z.string().url(),
})
});
export const collections = { blog, authors };

此示例博客文章指定相关帖子的 id 和帖子作者的 id

¥This example blog post specifies the ids of related posts and the id of the post author:

src/data/blog/welcome.md
---
title: "Welcome to my blog"
author: ben-holmes # references `src/data/authors/ben-holmes.json`
relatedPosts:
- about-me # references `src/data/blog/about-me.md`
- my-year-in-review # references `src/data/blog/my-year-in-review.md`
---

¥Defining custom IDs

当将 glob() 加载器与 Markdown、MDX、Markdoc 或 JSON 文件一起使用时,每个内容条目 id 都会根据内容文件名自动以 URL 友好格式生成。id 用于直接从你的集合中查询条目。当从你的内容创建新页面和 URL 时,它也很有用。

¥When using the glob() loader with Markdown, MDX, Markdoc, or JSON files, every content entry id is automatically generated in an URL-friendly format based on the content filename. The id is used to query the entry directly from your collection. It is also useful when creating new pages and URLs from your content.

你可以通过将自己的 slug 属性添加到文件前置内容或 JSON 文件的数据对象来覆盖条目生成的 id。这类似于其他 Web 框架的“永久链接”功能。

¥You can override an entry’s generated id by adding your own slug property to the file frontmatter or data object for JSON files. This is similar to the “permalink” feature of other web frameworks.

src/blog/1.md
---
title: My Blog Post
slug: my-custom-id/supports/slashes
---
Your blog post content here.
src/categories/1.json
{
"title": "My Category",
"slug": "my-custom-id/supports/slashes",
"description": "Your category description here."
}

¥Querying Collections

Astro 提供了辅助函数来查询集合并返回一个(或多个)内容条目。

¥Astro provides helper functions to query a collection and return one (or more) content entries.

这些返回具有唯一 id 的条目、具有所有已定义属性的 data 对象,并且还将返回包含 Markdown、MDX 或 Markdoc 文档的原始、未编译主体的 body

¥These return entries with a unique id, a data object with all defined properties, and will also return a body containing the raw, uncompiled body of a Markdown, MDX, or Markdoc document.

import { getCollection, getEntry } from 'astro:content';
// Get all entries from a collection.
// Requires the name of the collection as an argument.
const allBlogPosts = await getCollection('blog');
// Get a single entry from a collection.
// Requires the name of the collection and `id`
const poodleData = await getEntry('dogs', 'poodle');
See the full list of properties returned by the CollectionEntry type.

使用 Astro 模板中的内容

标题部分 使用 Astro 模板中的内容

¥Using content in Astro templates

查询集合后,你可以直接在 Astro 组件模板内访问每个条目的内容。例如,你可以创建一个指向你的博客文章的链接列表,使用 data 属性显示来自条目前言的信息。

¥After querying your collections, you can access each entry’s content directly inside of your Astro component template. For example, you can create a list of links to your blog posts, displaying information from your entry’s frontmatter using the data property.

src/pages/index.astro
---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
---
<h1>My posts</h1>
<ul>
{posts.map(post => (
<li><a href={`/blog/${post.id}`}>{post.data.title}</a></li>
))}
</ul>

¥Rendering body content

查询后,你可以使用 render() 函数属性将 Markdown 和 MDX 条目渲染为 HTML。调用此函数可让你访问渲染的 HTML 内容,包括 <Content /> 组件和所有渲染标题的列表。

¥Once queried, you can render Markdown and MDX entries to HTML using the render() function property. Calling this function gives you access to rendered HTML content, including both a <Content /> component and a list of all rendered headings.

src/pages/blog/post-1.astro
---
import { getEntry, render } from 'astro:content';
const entry = await getEntry('blog', 'post-1');
const { Content, headings } = await render(entry);
---
<p>Published on: {entry.data.published.toDateString()}</p>
<Content />

将内容作为属性传递

标题部分 将内容作为属性传递

¥Passing content as props

组件还可以将整个集合条目作为 prop 传递。

¥A component can also pass an entire collection entry as a prop.

你可以使用 CollectionEntry 实用程序使用 TypeScript 正确输入组件的 props。此实用程序采用与你的集合架构名称匹配的字符串参数,并将继承该集合架构的所有属性。

¥You can use the CollectionEntry utility to correctly type your component’s props using TypeScript. This utility takes a string argument that matches the name of your collection schema and will inherit all of the properties of that collection’s schema.

src/components/BlogCard.astro
---
import type { CollectionEntry } from 'astro:content';
interface Props {
post: CollectionEntry<'blog'>;
}
// `post` will match your 'blog' collection schema type
const { post } = Astro.props;
---

¥Filtering collection queries

getCollection() 采用可选的 “filter” 回调,允许你根据条目的 iddata 属性过滤查询。

¥getCollection() takes an optional “filter” callback that allows you to filter your query based on an entry’s id or data properties.

你可以使用它来按你喜欢的任何内容标准进行过滤。例如,你可以按 draft 等属性进行过滤,以防止任何草稿博客文章发布到你的博客:

¥You can use this to filter by any content criteria you like. For example, you can filter by properties like draft to prevent any draft blog posts from publishing to your blog:

// Example: Filter out content entries with `draft: true`
import { getCollection } from 'astro:content';
const publishedBlogEntries = await getCollection('blog', ({ data }) => {
return data.draft !== true;
});

你还可以创建在运行开发服务器时可用但不在生产中构建的草稿页面:

¥You can also create draft pages that are available when running the dev server, but not built in production:

// Example: Filter out content entries with `draft: true` only when building for production
import { getCollection } from 'astro:content';
const blogEntries = await getCollection('blog', ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true;
});

filter 参数还支持按集合中的嵌套目录进行过滤。由于 id 包含完整的嵌套路径,因此你可以按每个 id 的开头进行过滤,以仅返回特定嵌套目录中的项目:

¥The filter argument also supports filtering by nested directories within a collection. Since the id includes the full nested path, you can filter by the start of each id to only return items from a specific nested directory:

// Example: Filter entries by sub-directory in the collection
import { getCollection } from 'astro:content';
const englishDocsEntries = await getCollection('docs', ({ id }) => {
return id.startsWith('en/');
});

¥Accessing referenced data

首次查询你的集合条目后,必须单独查询任何 架构中定义的引用。你可以使用 getEntry() 函数返回单个引用项,或使用 getEntries() 从返回的 data 对象中检索多个引用条目。

¥Any references defined in your schema must be queried separately after first querying your collection entry. You can use the getEntry() function to return a single referenced item, or getEntries() to retrieve multiple referenced entries from the returned data object.

src/pages/blog/welcome.astro
---
import { getEntry, getEntries } from 'astro:content';
const blogPost = await getEntry('blog', 'welcome');
// Resolve a singular reference
const author = await getEntry(blogPost.data.author);
// Resolve an array of references
const relatedPosts = await getEntries(blogPost.data.relatedPosts);
---
<h1>{blogPost.data.title}</h1>
<p>Author: {author.data.name}</p>
<!-- ... -->
<h2>You might also like:</h2>
{relatedPosts.map(post => (
<a href={post.id}>{post.data.title}</a>
))}

¥Generating Routes from Content

内容集合存储在 src/pages/ 目录之外。这意味着默认情况下不会为你的集合项生成任何页面或路由。

¥Content collections are stored outside of the src/pages/ directory. This means that no pages or routes are generated for your collection items by default.

如果你想为每个集合条目(例如单个博客文章)生成 HTML 页面,则需要手动创建一个新的 动态路由。你的动态路由将映射传入的请求参数(例如 src/pages/blog/[...slug].astro 中的 Astro.params.slug)以获取每个页面的正确条目。

¥You will need to manually create a new dynamic route if you want to generate HTML pages for each of your collection entries, such as individual blog posts. Your dynamic route will map the incoming request param (e.g. Astro.params.slug in src/pages/blog/[...slug].astro) to fetch the correct entry for each page.

生成路由的具体方法取决于你的页面是预渲染(默认)还是由服务器按需渲染。

¥The exact method for generating routes will depend on whether your pages are prerendered (default) or rendered on demand by a server.

构建静态输出(默认)

标题部分 构建静态输出(默认)

¥Building for static output (default)

如果你正在构建静态网站(Astro 的默认行为),请在构建期间使用 getStaticPaths() 函数从单个页面组件(例如 src/pages/[slug])创建多个页面。

¥If you are building a static website (Astro’s default behavior), use the getStaticPaths() function to create multiple pages from a single page component (e.g. src/pages/[slug]) during your build.

getStaticPaths() 中调用 getCollection() 以使你的集合数据可用于构建静态路由。然后,使用每个内容条目的 id 属性创建单独的 URL 路径。每个页面都将整个集合条目作为 在页面模板中使用 的 prop 传递。

¥Call getCollection() inside of getStaticPaths() to have your collection data available for building static routes. Then, create the individual URL paths using the id property of each content entry. Each page is passed the entire collection entry as a prop for use in your page template.

src/pages/posts/[id].astro
---
import { getCollection, render } from 'astro:content';
// 1. Generate a new path for every collection entry
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map(post => ({
params: { id: post.id },
props: { post },
}));
}
// 2. For your template, you can get the entry directly from the prop
const { post } = Astro.props;
const { Content } = await render(post);
---
<h1>{post.data.title}</h1>
<Content />

这将为 blog 集合中的每个条目生成页面路由。例如,src/blog/hello-world.md 处的条目将具有 hello-worldid,因此其最终 URL 将为 /posts/hello-world/

¥This will generate a page route for every entry in the blog collection. For example, an entry at src/blog/hello-world.md will have an id of hello-world, and therefore its final URL will be /posts/hello-world/.

构建服务器输出 (SSR)

标题部分 构建服务器输出 (SSR)

¥Building for server output (SSR)

如果你正在构建动态网站(使用 Astro 的 SSR 支持),则不需要在构建过程中提前生成任何路径。相反,你的页面应该检查请求(使用 Astro.requestAstro.params)以按需查找 slug,然后使用 getEntry() 获取它。

¥If you are building a dynamic website (using Astro’s SSR support), you are not expected to generate any paths ahead of time during the build. Instead, your page should examine the request (using Astro.request or Astro.params) to find the slug on-demand, and then fetch it using getEntry().

src/pages/posts/[id].astro
---
import { getEntry, render } from "astro:content";
// 1. Get the slug from the incoming server request
const { id } = Astro.params;
if (id === undefined) {
return Astro.redirect("/404");
}
// 2. Query for the entry directly using the request slug
const post = await getEntry("blog", id);
// 3. Redirect if the entry does not exist
if (post === undefined) {
return Astro.redirect("/404");
}
// 4. Render the entry to HTML in the template
const { Content } = await render(post);
---
<h1>{post.data.title}</h1>
<Content />

¥When to create a collection

只要你有一组共享共同结构的相关数据或内容,你就可以随时 创建集合

¥You can create a collection any time you have a group of related data or content that shares a common structure.

使用集合的大部分好处来自:

¥Much of the benefit of using collections comes from:

  • 定义通用数据形状以验证单个条目是 “correct” 还是 “complete”,避免生产中的错误。

  • 以内容为中心的 API 旨在使查询在导入和渲染页面上的内容时变得直观(例如,getCollection() 而不是 import.meta.glob())。

  • 用于检索内容的 内容加载器 API,它提供内置加载器和对低级 API 的访问。有几种第三方和社区构建的加载器可用,你可以构建自己的自定义加载器以从任何地方获取数据。

  • 性能和可扩展性。内容层 API 允许在构建之间缓存数据,适用于数以万计的内容条目。

定义你的数据 作为集合时:

¥Define your data as a collection when:

  • 你有多个文件或数据需要组织,它们共享相同的整体结构(例如,用 Markdown 编写的博客文章都具有相同的前置属性)。

  • 你有远程存储的现有内容,例如在 CMS 中,并且想要利用集合辅助函数和内容层 API,而不是使用 fetch() 或 SDK。

  • 你需要获取(数)万个相关数据,并且需要一种能够大规模处理的查询和缓存方法。

¥When not to create a collection

当你有多个必须共享相同属性的内容时,集合提供了出色的结构、安全性和组织。

¥Collections provide excellent structure, safety, and organization when you have multiple pieces of content that must share the same properties.

如果出现以下情况,集合可能不是你的解决方案:

¥Collections may not be your solution if:

  • 你只有一个或少数不同的页面。直接将 制作单个页面组件(例如 src/pages/about.astro)与你的内容一起考虑。

  • 你正在显示 Astro 未处理的文件,例如 PDF。将这些静态资源放在项目的 public/ 目录 中。

  • 你的数据源有自己的 SDK/客户端库用于导入,它与内容加载器不兼容或不提供内容加载器,并且你更喜欢直接使用它。

  • 你正在使用需要实时更新的 API。内容集合仅在构建时更新,因此如果你需要实时数据,请将 importing files获取数据 的其他方法与 按需渲染 一起使用。

Astro 中文网 - 粤ICP备13048890号