✨Kevin‘s Blog🪐

第 7 课:多级路由支持(动态 slug 路由)

📅发布日期:7/13/2025

在这一课中,我们将实现 Astro 博客中的「多级目录支持」,使文章可以使用类似 /blog/astro/lesson-7-slug-routing 的路径结构,而不是扁平的 /blog/lesson-7


✨ 效果展示


🧠 背景原理

Astro 的动态路由 [...slug].astro 用于捕获多段路径,例如:

/blog/astro/lesson-7-slug-routing -> [...slug] = ["astro", "lesson-7-slug-routing"]

但需要注意:

🔥 getStaticPaths() 返回的 params.slug 必须是 字符串 而不是数组,否则会报错!

这是 Astro 的设计特性 —— 即使你定义了 [...slug].astro,它仍然要求 params.slug 是字符串。


📁 内容结构调整

将你的博客文章组织为多级目录:

src/content/blog/
├── linux/
   └── 1.md
└── astro/
    ├── lesson-6-card-layout.md
    └── lesson-7-slug-routing.md

这样,slug 将自动变为:


🧩 配置 getStaticPaths

src/pages/blog/[...slug].astro:

export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map((post) => ({
    params: { slug: post.slug }, // ✅ 注意:不能 .split("/")
    props: post,
  }));
}

:::caution 注意 不要写成:

params: { slug: post.slug.split("/") } // ❌ 会报错!

否则会报错:

Invalid getStaticPaths route parameter for slug. Expected string, received array

✅ 页面完整代码

---
import { type CollectionEntry, getCollection } from 'astro:content';
import Layout from '../../layouts/Layout.astro';
import { render } from 'astro:content';

export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: post,
  }));
}

type Props = CollectionEntry<'blog'>;
const post = Astro.props;
const { Content } = await render(post);
---

<Layout>
  <h1>{post.data.title}</h1>
  <p>📅 {post.data.pubDate.toLocaleDateString()}</p>
  <Content />
</Layout>

📝 小结


下一课我们将进入第 8 课:离线全文搜索(基于 JSON 构建索引 + 前端搜索)