5 • 增强你的博客

生成标签页面

准备好…

  • 创建一个页面以生成多个页面
  • 指定要构建的页面路由,并为每个页面传递各自的属性

你可以使用 .astro 文件创建整套动态页面,这些文件需要向外暴露一个 getStaticPaths() 函数。

  1. 创建一个新文件:src/pages/tags/[tag].astro。(你需要创建一个新文件夹。)注意文件名([tag].astro)使用方括号。将以下代码粘贴到文件中:

    src/pages/tags/[tag].astro
    ---
    import BaseLayout from '../../layouts/BaseLayout.astro';
    export async function getStaticPaths() {
    return [
    { params: { tag: "astro" } },
    { params: { tag: "successes" } },
    { params: { tag: "community" } },
    { params: { tag: "blogging" } },
    { params: { tag: "setbacks" } },
    { params: { tag: "learning in public" } },
    ];
    }
    const { tag } = Astro.params;
    ---
    <BaseLayout pageTitle={tag}>
    <p>Posts tagged with {tag}</p>
    </BaseLayout>

    getStaticPaths 函数返回一个页面路由数组,这些页面将使用文件中定义的相同模板。

  2. 如果你已经自定义了博客文章,用你自己的文章中使用的标签替换各个标签值(例如 “astro”、“successes”、“community” 等)。

  3. 确保每篇博客文章至少包含一个标签,以数组的形式编写,例如 tags: ["blogging"]

  4. 在浏览器中访问 localhost:3000/tags/astro,你应该能看到一个页面,它是从 [tag].astro 动态生成的。检查是否还为每个标签创建了页面,例如 /tags/successes/tags/community/tags/learning%20in%20public 等,或者你自定义的标签。你可能需要先退出并重新启动开发服务器才能看到这些新页面。

在动态路由中使用 props

标题部分 在动态路由中使用 props
  1. 在你的 getStaticPaths() 函数中添加以下 props,以便使所有博客文章的数据对每个页面路由可用。

    确保为数组中的每个路由都添加新的 props,并将这些 props 在函数之外的组件模板中可用。

    src/pages/tags/[tag].astro
    ---
    import BaseLayout from '../../layouts/BaseLayout.astro';
    export async function getStaticPaths() {
    const allPosts = await Astro.glob('../posts/*.md');
    return [
    {params: {tag: "astro"}, props: {posts: allPosts}},
    {params: {tag: "successes"}, props: {posts: allPosts}},
    {params: {tag: "community"}, props: {posts: allPosts}},
    {params: {tag: "blogging"}, props: {posts: allPosts}},
    {params: {tag: "setbacks"}, props: {posts: allPosts}},
    {params: {tag: "learning in public"}, props: {posts: allPosts}}
    ]
    }
    const { tag } = Astro.params;
    const { posts } = Astro.props;
    ---
  2. 将文章列表筛选为仅包含页面所属标签的文章。

    /src/pages/tags/[tag].astro
    ---
    const { tag } = Astro.params;
    const { posts } = Astro.props;
    const filteredPosts = posts.filter((post) => post.frontmatter.tags?.includes(tag));
    ---
  3. 现在,你可以更新 HTML 模板以显示包含页面所属标签的每篇博客文章列表。将以下代码添加到 [tag].astro

    src/pages/tags/[tag].astro
    <BaseLayout pageTitle={tag}>
    <p>Posts tagged with {tag}</p>
    <ul>
    {filteredPosts.map((post) => <li><a href={post.url}>{post.frontmatter.title}</a></li>)}
    </ul>
    </BaseLayout>
  4. 你甚至可以将此代码重构为使用 <BlogPost /> 组件!(不要忘记在 [tag].astro 的顶部导入该组件。)

    src/pages/tags/[tag].astro
    <BaseLayout pageTitle={tag}>
    <p>Posts tagged with {tag}</p>
    <ul>
    {filteredPosts.map((post) => <li><a href={post.url}>{post.frontmatter.title}</a></li>)}
    {filteredPosts.map((post) => <BlogPost url={post.url} title={post.frontmatter.title}/>)}
    </ul>
    </BaseLayout>
  5. 在浏览器中的预览中查看各个标签页面,现在你应该能看到包含特定标签的所有博客文章列表。

对于以下每个问题,请指出代码是在 getStaticPath() 函数的内部还是在其外部编写的。

  1. Astro.glob() 调用以接收有关所有 .md 文件的信息,并将其传递给每个页面路由。

  2. getStaticPaths() 要生成(返回的)路由列表的代码。

  3. 用于在 HTML 模板中使用的 propsparams 的值。

进阶 JavaScript:从现有标签生成页面

标题部分 进阶 JavaScript:从现有标签生成页面

现在,你的标签页面在 [tag].astro 中静态定义。如果你在博客文章中添加了新标签,你还必须重新访问该页面并更新你的页面路由。

以下示例显示了如何用新的代码替换此页面上的代码,该代码将自动查找并为博客页面上使用的每个标签生成页面。

1. 检查所有博客文章是否包含标签

标题部分 1. 检查所有博客文章是否包含标签

重新访问你的现有 Markdown 页面,确保每篇文章的前置数据中都包含一个 tags 数组。即使只有一个标签,它也应该被写成一个数组,例如 tags: ["blogging"]

2. 创建包含所有现有标签的数组

标题部分 2. 创建包含所有现有标签的数组

添加以下代码,以提供一个包含博客文章中使用的每个标签的列表。

src/pages/tags/[tag].astro
---
import BaseLayout from '../../layouts/BaseLayout.astro';
export async function getStaticPaths() {
const allPosts = await Astro.glob('../posts/*.md');
const uniqueTags = [...new Set(allPosts.map((post) => post.frontmatter.tags).flat())];
请详细说明这行代码正在做什么!

毕竟这不是你自己编写的代码,看不懂是正常的!

它逐个处理每个 Markdown 文章,并将每个标签数组组合成一个更大的数组。然后,它从找到的所有标签创建一个新的 Set(以忽略重复值)。最后,它将该 Set 转换为一个数组(不重复的),你可以用它来显示页面上的标签列表。

现在,你有一个名为 uniqueTags 的数组,其中包含元素项 "astro""successes""community""blogging""setbacks""learning in public"

3. 替换 getStaticPaths 函数的 return

标题部分 3. 替换 getStaticPaths 函数的 return 值
src/pages/tags/[tag].astro
return [
{params: {tag: "astro"}, props: {posts: allPosts}},
{params: {tag: "successes"}, props: {posts: allPosts}},
{params: {tag: "community"}, props: {posts: allPosts}},
{params: {tag: "blogging"}, props: {posts: allPosts}},
{params: {tag: "setbacks"}, props: {posts: allPosts}},
{params: {tag: "learning in public"}, props: {posts: allPosts}}
]
return uniqueTags.map((tag) => {
const filteredPosts = allPosts.filter((post) => post.frontmatter.tags.includes(tag));
return {
params: { tag },
props: { posts: filteredPosts },
};
});

getStaticPaths 函数应始终返回一个包含 params(用于每个页面路由的名称)的对象列表,并且可以选择包含任何 props(要传递给这些页面的数据)。之前,你为你所知道的每个博客中使用的标签名称定义了一个参数,并将整个文章列表作为 props 传递给每个页面。

现在,你可以使用 uniqueTags 数组自动生成此对象列表,以定义每个参数。

现在,在将文章列表作为 props 发送到每个页面之前,应在此之前对其进行过滤。确保删除以前过滤文章的代码行,并更新 HTML 模板以使用 posts 而不是 filteredPosts

src/pages/tags/[tag].astro
const { tag } = Astro.params;
const { posts } = Astro.props;
const filteredPosts = posts.filter((post) => post.frontmatter.tags.includes(tag));
---
<!-- -->
<ul>
{filteredPosts.map((post) => <BlogPost url={post.url} title={post.frontmatter.title}/>)}
{posts.map((post) => <BlogPost url={post.url} title={post.frontmatter.title}/>)}
</ul>

为了检查你的工作,或者如果你只想要完整、正确的代码以便复制到 [tag].astro 文件中,下面是你的 Astro 组件应该是这样的:

src/pages/tags/[tag].astro
---
import BaseLayout from '../../layouts/BaseLayout.astro';
import BlogPost from '../../components/BlogPost.astro';
export async function getStaticPaths() {
const allPosts = await Astro.glob('../posts/*.md');
const uniqueTags = [...new Set(allPosts.map((post) => post.frontmatter.tags).flat())];
return uniqueTags.map((tag) => {
const filteredPosts = allPosts.filter((post) => post.frontmatter.tags.includes(tag));
return {
params: { tag },
props: { posts: filteredPosts },
};
});
}
const { tag } = Astro.params;
const { posts } = Astro.props;
---
<BaseLayout pageTitle={tag}>
<p>包含「{tag}」标签的文章</p>
<ul>
{posts.map((post) => <BlogPost url={post.url} title={post.frontmatter.title}/>)}
</ul>
</BaseLayout>

现在,你应该能够在浏览器预览中访问任何一个标签页面。

在浏览器中导航到 localhost:3000/tags/community,你应该看到一个包含标签为 community 的博文列表。同样地,localhost:3000/tags/learning%20in%20public 应该显示一个包含标签为 learning in public 的博文列表。

在接下来的部分,你将创建导航链接到这些页面。

选择与描述相匹配的术语。

  1. 返回一个页面路由数组的函数。

  2. 从一个文件中创建多个页面路由的过程。

  3. 定义动态生成的页面路由名称的值。