全书目录

第三十五篇:Astro 完全指南 —— 内容展馆群岛宇宙

第十章:内容集合与内容层,是群岛的展品档案总库

1 分钟 226 字 第 662 / 962 个阅读单元

Astro 真正的王牌,不只是页面快,而是它对内容管理这件事做得非常顺。

它有一整套内容层心智:

  • 内容不是随手 import 一下就完
  • 内容可以有结构
  • 内容要有 schema
  • 内容要能安全查询
  • 内容和路由、渲染、类型系统最好连起来

这就是 content collections / content layer

一个典型的内容配置:

ts
// src/content.config.ts
import { defineCollection, reference, z } from 'astro:content';
import { glob } from 'astro/loaders';

const authors = defineCollection({
  loader: glob({ pattern: '**/*.json', base: './src/data/authors' }),
  schema: z.object({
    name: z.string(),
    role: z.string(),
    avatar: z.string().optional(),
  }),
});

const exhibitions = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/data/exhibitions' }),
  schema: z.object({
    title: z.string(),
    summary: z.string(),
    publishDate: z.coerce.date(),
    cover: z.string(),
    tags: z.array(z.string()).default([]),
    author: reference('authors'),
  }),
});

export const collections = { authors, exhibitions };

然后在页面里查询:

astro
---
import { getCollection } from 'astro:content';

const exhibitions = (await getCollection('exhibitions'))
  .sort((a, b) => b.data.publishDate.getTime() - a.data.publishDate.getTime());
---

<ul>
  {exhibitions.map((item) => (
    <li>
      <a href={`/exhibitions/${item.id}/`}>
        {item.data.title}
      </a>
      <p>{item.data.summary}</p>
    </li>
  ))}
</ul>

把这套东西翻成展馆语言:

text
Collection = 某一类展品档案库
Schema     = 每类展品必须填写的档案字段
getCollection() = 调出整库档案
getEntry()      = 调出单件展品
reference()     = 档案之间的关联索引
render()        = 把展品正文真正展开成可展示内容

这比“把 Markdown 文件当普通文件乱读一通”高了一个层级。