跳转到内容

构建一个标签索引页

现在你已经为每个标签创建了单独的页面,是时候为它们创建链接了。

准备好去……

  • 使用 /pages/folder/index.astro 路由模式添加一个新页面
  • 显示所有唯一标签的列表,并链接到每个标签页面
  • 更新你的网站,添加指向这个新标签页面的导航链接

要将标签索引页添加到你的网站,你可以在 src/pages/tags.astro 创建一个新文件。

但是,由于你已经有了 /tags/ 目录,你可以利用 Astro 的另一种路由模式,并将所有与标签相关的文件放在一起。

  1. src/pages/tags/ 目录中创建一个新文件 index.astro

  2. 导航到 https://:4321/tags 并验证你的网站现在在此 URL 上包含一个页面。它将是空的,但它确实存在。

  3. src/pages/tags/index.astro 创建一个使用你的布局的最小化页面。你以前做过这个!

    展开以查看步骤
    1. src/pages/tags/ 中创建一个新的页面组件。

      显示文件名
      index.astro
    2. 导入并使用你的 <BaseLayout>

      显示代码
      src/pages/tags/index.astro
      ---
      import BaseLayout from '../../layouts/BaseLayout.astro';
      ---
      <BaseLayout></BaseLayout>
    3. 定义一个页面标题,并将其作为组件属性传递给你的布局。

      显示代码
      src/pages/tags/index.astro
      ---
      import BaseLayout from '../../layouts/BaseLayout.astro';
      const pageTitle = "Tag Index";
      ---
      <BaseLayout pageTitle={pageTitle}></BaseLayout>
  4. 再次检查你的浏览器预览,你应该会看到一个格式化的页面,准备好添加内容了!

你之前已经使用 map() 从数组中显示列表项。如果定义一个包含所有标签的数组,然后在这个页面上以列表形式显示它们,会是什么样子?

查看代码
src/pages/tags/index.astro
---
import BaseLayout from '../../layouts/BaseLayout.astro';
const tags = ['astro', 'blogging', 'learning in public', 'successes', 'setbacks', 'community']
const pageTitle = "Tag Index";
---
<BaseLayout pageTitle={pageTitle}>
<ul>
{tags.map((tag) => <li>{tag}</li>)}
</ul>
</BaseLayout>

你可以这样做,但这样一来,每次你在未来的博客文章中使用新标签时,都需要回到这个文件来更新你的数组。

幸运的是,你已经知道一种方法,可以用一行代码从所有 Markdown 文件中获取数据,然后返回所有标签的列表。

  1. src/pages/tags/index.astro 中,将那行代码添加到 frontmatter 脚本中,这将使你的页面能够访问每个 .md 博客文章文件的数据。

    查看代码
    src/pages/tags/index.astro
    ---
    import BaseLayout from '../../layouts/BaseLayout.astro';
    const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
    const pageTitle = "Tag Index";
    ---
  2. 接下来,将以下这行 JavaScript 添加到你的页面组件中。这与你在 src/pages/tags/[tag].astro 中使用的依赖 Astro 内置 TypeScript 支持的代码相同,用于返回唯一标签的列表。

    src/pages/tags/index.astro
    ---
    import BaseLayout from '../../layouts/BaseLayout.astro';
    const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
    const tags = [...new Set(allPosts.map((post: any) => post.frontmatter.tags).flat())];
    const pageTitle = "Tag Index";
    ---

这次不是在无序列表中创建项目,而是在一个 <div> 内部为每个项目创建一个 <p>。这个模式看起来应该很熟悉!

  1. 将以下代码添加到你的组件模板中

    src/pages/tags/index.astro
    <BaseLayout pageTitle={pageTitle}>
    <div>{tags.map((tag) => <p>{tag}</p>)}</div>
    </BaseLayout>

    在你的浏览器预览中,验证你是否能看到列出的标签。如果任何博客文章缺少标签,或者它们的格式不正确,Astro 的内置 TypeScript 支持将向你显示错误,以便你检查和更正你的代码。

  2. 为了使每个标签链接到其自己的页面,为每个标签名称添加以下 <a> 链接

    src/pages/tags/index.astro
    <BaseLayout pageTitle={pageTitle}>
    <div>
    {tags.map((tag) => (
    <p><a href={`/tags/${tag}`}>{tag}</a></p>
    ))}
    </div>
    </BaseLayout>
  1. 添加以下 CSS 类来为你的 <div> 和将要生成的每个 <p> 设置样式。注意:Astro 使用 HTML 语法添加类名!

    src/pages/tags/index.astro
    <BaseLayout pageTitle={pageTitle}>
    <div class="tags">
    {tags.map((tag) => (
    <p class="tag"><a href={`/tags/${tag}`}>{tag}</a></p>
    ))}
    </div>
    </BaseLayout>
  2. 通过将以下 <style> 标签添加到此页面来定义这些新的 CSS 类

    src/pages/tags/index.astro
    <style>
    a {
    color: #00539F;
    }
    .tags {
    display: flex;
    flex-wrap: wrap;
    }
    .tag {
    margin: 0.25em;
    border: dotted 1px #a1a1a1;
    border-radius: .5em;
    padding: .5em 1em;
    font-size: 1.15em;
    background-color: #F8FCFD;
    }
    </style>
  3. https://:4321/tags 检查你的浏览器预览,以验证你已应用一些新样式,并且页面上的每个标签都有一个指向其各自标签页面的有效链接。

这是你的新页面应该看起来的样子

src/pages/tags/index.astro
---
import BaseLayout from '../../layouts/BaseLayout.astro';
const allPosts = Object.values(import.meta.glob('../posts/*.md', { eager: true }));
const tags = [...new Set(allPosts.map((post: any) => post.frontmatter.tags).flat())];
const pageTitle = "Tag Index";
---
<BaseLayout pageTitle={pageTitle}>
<div class="tags">
{tags.map((tag) => (
<p class="tag"><a href={`/tags/${tag}`}>{tag}</a></p>
))}
</div>
</BaseLayout>
<style>
a {
color: #00539F;
}
.tags {
display: flex;
flex-wrap: wrap;
}
.tag {
margin: 0.25em;
border: dotted 1px #a1a1a1;
border-radius: .5em;
padding: .5em 1em;
font-size: 1.15em;
background-color: #F8FCFD;
}
</style>

现在,你可以导航到 https://:4321/tags 并看到这个页面。在这个页面上,你可以点击链接到你各自的标签页面。

但是,你仍然需要让你网站上的其他页面能够发现这些页面。

  1. 在你的 Navigation.astro 组件中,包含一个指向这个新标签索引页的链接。

    给我看代码
    src/components/Navigation.astro
    <a href="/">Home</a>
    <a href="/about/">About</a>
    <a href="/blog/">Blog</a>
    <a href="/tags/">Tags</a>

挑战:在你的博客文章布局中包含标签

标题为“挑战:在你的博客文章布局中包含标签”的部分

你现在已经编写了所有需要的代码,也可以在每篇博客文章上显示标签列表,并将它们链接到各自的标签页面。你可以重用已有的工作!

按照以下步骤操作,然后通过与最终代码示例比较来检查你的工作。

  1. src/pages/tags/index.astro 复制 <div class="tags">...</div><style>...</style>,并在 MarkdownPostLayout.astro 内部重用它

    src/layouts/MarkdownPostLayout.astro
    ---
    import BaseLayout from './BaseLayout.astro';
    const { frontmatter } = Astro.props;
    ---
    <BaseLayout pageTitle={frontmatter.title}>
    <p><em>{frontmatter.description}</em></p>
    <p>{frontmatter.pubDate.toString().slice(0,10)}</p>
    <p>Written by: {frontmatter.author}</p>
    <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />
    <div class="tags">
    {tags.map((tag: string) => (
    <p class="tag"><a href={`/tags/${tag}`}>{tag}</a></p>
    ))}
    </div>
    <slot />
    </BaseLayout>
    <style>
    a {
    color: #00539F;
    }
    .tags {
    display: flex;
    flex-wrap: wrap;
    }
    .tag {
    margin: 0.25em;
    border: dotted 1px #a1a1a1;
    border-radius: .5em;
    padding: .5em 1em;
    font-size: 1.15em;
    background-color: #F8FCFD;
    }
    </style>

在这段代码生效之前,你需要对粘贴到 MarkdownPostLayout.astro 中的代码进行一个小小的编辑。你能找出是什么吗?

给我一个提示

其他 props(例如 title、author 等)在你的布局模板中是如何编写的?你的布局是如何从单篇博客文章中接收 props 的?

再给我一个提示!

为了在你的布局中使用来自 .md 博客文章的 props(传递的值),比如标签,你需要在值前面加上一个特定的词。

显示代码!
src/layouts/MarkdownPostLayout.astro
<div class="tags">
{frontmatter.tags.map((tag: string) => (
<p class="tag"><a href={`/tags/${tag}`}>{tag}</a></p>
))}
</div>

要检查你的工作,或者你只是想将完整、正确的代码复制到 MarkdownPostLayout.astro 中,这里是你的 Astro 组件应该看起来的样子

src/layouts/MarkdownPostLayout.astro
---
import BaseLayout from './BaseLayout.astro';
const { frontmatter } = Astro.props;
---
<BaseLayout pageTitle={frontmatter.title}>
<p><em>{frontmatter.description}</em></p>
<p>{frontmatter.pubDate.toString().slice(0,10)}</p>
<p>Written by: {frontmatter.author}</p>
<img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />
<div class="tags">
{frontmatter.tags.map((tag: string) => (
<p class="tag"><a href={`/tags/${tag}`}>{tag}</a></p>
))}
</div>
<slot />
</BaseLayout>
<style>
a {
color: #00539F;
}
.tags {
display: flex;
flex-wrap: wrap;
}
.tag {
margin: 0.25em;
border: dotted 1px #a1a1a1;
border-radius: .5em;
padding: .5em 1em;
font-size: 1.15em;
background-color: #F8FCFD;
}
</style>

将每个文件路径与将在相同路由下创建页面的另一个文件路径匹配。

  1. src/pages/categories.astro

  2. src/pages/posts.astro

  3. src/pages/products/shoes/index.astro

贡献 社区 赞助