- 起步
- 核心概念
- 教程
- 基础内容
- 内置功能
- 集成
- 操作指南
- 使用指南
- 配置
- 参考
- 社区资源
- 其他
- 为文档做出贡献
- 手动安装 Astro
- 升级到 Astro v4
- 升级到 Astro v3
- 升级到 Astro v2
- Legacy v0.x Upgrade Guide
- 从 Create React App(CRA)迁移
- 关于本教程
- 第一单元:前期准备
- 准备开发环境
- 创建你的第一个 Astro 项目
- 你的第一行 Astro 代码
- 创建在线代码仓库
- 将你的网站部署到网络
- 第二单元:页面
- 创建你的第一个 Astro 页面
- 编写你的第一篇 Markdown 博客文章
- 添加「关于你」的动态内容
- 给你的「关于」页面添加样式
- 应用全局样式
- 第三单元:组件
- 创建一个可重复使用的导航组件
- 创建社交媒体 footer
- 自己动手搭建导航 Header
- 编写你的第一个浏览器脚本
- 第四单元:布局
- 编写你的第一个布局
- 创建并传递数据到博客布局
- 布局结合,两全其美
- 第五单元 - Astro API
- 创建文章存档页
- 生成标签页面
- 编写标签索引页面
- 添加 RSS 订阅源
- 第六单元 - Astro 群岛
- 搭建你的第一个 Astro 岛屿
- 回到干燥的陆地。让你的博客从白天到黑夜,无需岛屿!
- 恭喜你!
- @astrojs/mdx
- 添加阅读时间
- 创建开发者工具栏应用
- @astrojs/alpinejs
- @astrojs/lit
- @astrojs/preact
- @astrojs/react
- @astrojs/solid-js
- @astrojs/svelte
- @astrojs/vue
- @astrojs/cloudflare
- @astrojs/netlify
- @astrojs/node
- @astrojs/vercel
- @astrojs/db
- @astrojs/markdoc
- @astrojs/partytown
- @astrojs/sitemap
- @astrojs/tailwind
- 使用流式处理来提升页面性能
- 从 Gatsby 迁移
- 从 Next.js 迁移
- 从 NuxtJS 迁移
- 从 Docusaurus 迁移到 Astro
- 从 Eleventy 迁移到 Astro
- 从 GitBook 迁移到 Astro
- 从Gridsome迁移到Astro
- 从 Hugo 迁移
- 从 Jekyll 迁移
- 从 Pelican 迁移
- 从 SvelteKit 迁移
- 从VuePress迁移
- 从 WordPress 迁移
- 状态共享
- Storyblok 与 Astro
- Contentful 与 Astro
- ButterCMS & Astro
- Builder.io & Astro
- Cosmic 与 Astro
- DatoCMS 与 Astro
- Front Matter CMS 与 Astro
- Ghost & Astro
- Hashnode & Astro
- Hygraph 与 Astro
- Keystatic & Astro
- Kontent.ai 与 Astro
- 无头模式的 Statamic 与 Astro
- Strapi 与 Astro
- Tina CMS 与 Astro
- Umbraco & Astro
- 无头(headless)模式的 WordPress 与 Astro
- ApostropheCMS 与 Astro
- Caisy & Astro
- CloudCannon与Astro
- Crystallize 与 Astro
- Decap CMS 与 Astro
- Directus 与 Astro
- KeystoneJS 与 Astro
- microCMS & Astro
- Payload CMS 与 Astro
- Prepr CMS & Astro
- Prismic & Astro
- Sanity & Astro
- Sitecore 体验管理器 & Astro
- Spinal & Astro
- 创作内容
- Firebase 与 Astro
- Supabase 与 Astro
- Turso 和 Astro
- Xata 与 Astro
- Appwrite & Astro
- 部署你的 Astro 站点至 Netlify
- 部署你的 Astro 站点至 Vercel
- 如何将你的 Astro 网站部署到 Deno
- 部署你的 Astro 站点至 GitHub Pages
- 部署你的 Astro 站点至 GitLab Pages
- 部署你的 Astro 站点至 Cloudflare Pages
- 将你的 Astro 网站部署到 AWS
- 将你的 Astro 网站通过 Flightcontrol 部署到 AWS
- 将你的 Astro 网站通过 SST 部署到 AWS
- 将你的 Astro 网站部署至 Google Cloud
- 部署你的 Astro 站点至 Google Firebase 托管
- 将你的 Astro 网站部署到 Heroku
- 将你的 Astro 网站部署到 Microsoft Azure
- 部署你的 Astro 站点至 Buddy
- 将你的 Astro 网站部署到 Edgio
- 将你的 Astro 站点部署到 Fly.io
- 将你的 Astro 网站部署到 Render
- 将你的 Astro 网站部署到 Stormkit
- 将你的 Astro 网站部署到 Surge
- 通过 Cleavr 部署你的 Astro 网站
- 将你的 Astro 站点部署到 Kinsta 应用托管
- 将你的 Astro 网站部署到 Space
- 将你的 Astro 站点部署到 Zeabur
- 将你的 Astro 网站部署到 Zerops
- 添加 RSS 摘要
- 安装一个 Vite 或 Rollup 插件
- 构建自定义图像组件
- 使用 API 路由构建表单
- 在 Astro 页面中构建 HTML 表单
- 在 Astro 中使用 Bun
- 调用服务器端点
- 校验验证码
- 用 Docker 来构建你的 Astro 网站
- 动态导入图片
- 为链接添加图标
- 添加 i18n 功能
- 添加最后修改时间
- 在 Astro 组件中共享状态
- 使用 Tailwind Typography 美化渲染后的 Markdown
- Unknown compiler error.
- Astro.redirect is not available in static mode.
- Astro.clientAddress is not available in current adapter.
- Astro.clientAddress cannot be used inside prerendered routes.
- Astro.clientAddress is not available in static mode.
- No static path found for requested path.
- Invalid type returned by Astro page.
- Missing value for client:media directive.
- No matching renderer found.
- No client entrypoint specified in renderer.
- Missing hint on client:only directive.
- Invalid value returned by a getStaticPaths path.
- Invalid entry inside getStaticPath's return value
- Invalid value returned by getStaticPaths.
- getStaticPaths RSS helper is not available anymore.
- Missing params property on getStaticPaths route.
- Invalid value for getStaticPaths route parameter.
- getStaticPaths() function required for dynamic routes.
- Invalid slot name.
- Cannot use Server-side Rendering without an adapter.
- No import found for component.
- Invalid prerender export.
- Invalid component arguments.
- Page number param not found.
- Image missing required "alt" property.
- Error while loading image service.
- Missing image dimensions
- Failed to retrieve remote image dimensions
- Unsupported image format
- Unsupported image conversion
- Prerendered dynamic endpoint has path collision.
- Expected src to be an image.
- Expected image options.
- Cannot set both densities and widths
- Image not found.
- Could not process image metadata.
- Image not found.
- Could not transform image.
- Unable to set response.
- The middleware didn't return a Response.
- The middleware returned something that is not a Response object.
- The endpoint did not return a Response.
- Value assigned to locals is not accepted.
- Astro.response.headers must not be reassigned.
- Can't load the middleware.
- Local images must be imported.
- Astro.glob() used outside of an Astro file.
- Astro.glob() did not match any files.
- A redirect must be given a location with the Location header.
- Invalid dynamic route.
- Could not find Sharp.
- Unknown Vite Error.
- Could not import file.
- Invalid glob pattern.
- Astro couldn't find the correct page to render
- The provided locale does not exist.
- Index page not found.
- You can't use the current function with the current strategy
- Prerendered routes aren't supported when internationalization domains are enabled.
- 启用了手动国际化路由但没有提供中间件。
- Astro can't render the route.
- Unhandled rejection
- i18n Not Enabled
- Route not found.
- Unknown CSS Error
- CSS Syntax Error
- Unknown Markdown Error.
- Failed to parse Markdown frontmatter.
- Invalid frontmatter injection.
- MDX integration missing.
- Unknown configuration error.
- Specified configuration file not found.
- Legacy configuration detected.
- Unknown CLI Error.
- Failed to generate content types.
- Unknown Content Collection Error.
- Content entry frontmatter does not match schema.
- Invalid content entry slug.
- Content Schema should not contain slug.
- Collection does not exist
- Content and data cannot be in same collection.
- Collection contains entries of a different type.
- Data collection entry failed to parse.
- Duplicate content entry slug.
- Actions must be used with server output.
- Unsupported transform in content config.
生成标签页面
准备好…
- 创建一个页面以生成多个页面
- 指定要构建的页面路由,并为每个页面传递各自的属性
动态页面路由
你可以使用 .astro
文件创建整套动态页面,这些文件需要向外暴露一个 getStaticPaths()
函数。
动态创建页面
创建一个新文件:
src/pages/tags/[tag].astrosrc/pages/tags/[tag].astro
。(你需要创建一个新文件夹。)注意文件名([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>包含「{tag}」标签的文章</p> </BaseLayout>
getStaticPaths
函数返回一个页面路由数组,这些页面将使用文件中定义的相同模板。如果你已经自定义了博客文章,用你自己的文章中使用的标签替换各个标签值(例如 “astro”、“successes”、“community” 等)。
确保每篇博客文章至少包含一个标签,以数组的形式编写,例如
tags: ["blogging"]
。在浏览器中访问
http://localhost:4321/tags/astro
,你应该能看到一个页面,它是从[tag].astro
动态生成的。检查是否还为每个标签创建了页面,例如/tags/successes
、/tags/community
、/tags/learning%20in%20public
等,或者你自定义的标签。你可能需要先退出并重新启动开发服务器才能看到这些新页面。
在动态路由中使用 props
在你的
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; ---
将文章列表筛选为仅包含页面所属标签的文章。
/src/pages/tags/[tag].astro--- const { tag } = Astro.params; const { posts } = Astro.props;const filteredPosts = posts.filter((post) => post.frontmatter.tags?.includes(tag)); ---
现在,你可以更新 HTML 模板以显示包含页面所属标签的每篇博客文章列表。将以下代码添加到
src/pages/tags/[tag].astro[tag].astro
:<BaseLayout pageTitle={tag}> <p>包含「{tag}」标签的文章</p> <ul> {filteredPosts.map((post) => <li><a href={post.url}>{post.frontmatter.title}</a></li>)} </ul> </BaseLayout>
你甚至可以将此代码重构为使用
src/pages/tags/[tag].astro<BlogPost />
组件!(不要忘记在[tag].astro
的顶部导入该组件。)<BaseLayout pageTitle={tag}> <p>包含「{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>
在浏览器中的预览中查看各个标签页面,现在你应该能看到包含特定标签的所有博客文章列表。
分析代码
对于以下每个问题,请指出代码是在 getStaticPath()
函数的内部还是在其外部编写的。
Astro.glob()
调用以接收有关所有.md
文件的信息,并将其传递给每个页面路由。getStaticPaths()
要生成(返回的)路由列表的代码。用于在 HTML 模板中使用的
props
和params
的值。
进阶 JavaScript:从现有标签生成页面
现在,你的标签页面在 [tag].astro
中静态定义。如果你在博客文章中添加了新标签,你还必须重新访问该页面并更新你的页面路由。
以下示例显示了如何用新的代码替换此页面上的代码,该代码将自动查找并为博客页面上使用的每个标签生成页面。
检查所有博客文章是否包含标签
重新访问你的现有 Markdown 页面,确保每篇文章的前置数据中都包含一个
tags
数组。即使只有一个标签,它也应该被写成一个数组,例如tags: ["blogging"]
。创建包含所有现有标签的数组
添加以下代码,以提供一个包含博客文章中使用的每个标签的列表。
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"
。替换
src/pages/tags/[tag].astrogetStaticPaths
函数的return
值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 模板以使用
src/pages/tags/[tag].astroposts
而不是filteredPosts
。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 组件应该是这样的:
---
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>
现在,你应该能够在浏览器预览中访问任何一个标签页面。
在浏览器中导航到 http://localhost:4321/tags/community
,你应该看到一个包含标签为 community
的博文列表。同样地,http://localhost:4321/tags/learning%20in%20public
应该显示一个包含标签为 learning in public
的博文列表。
在接下来的部分,你将创建导航链接到这些页面。
检验你的知识
选择与描述相匹配的术语。
返回一个页面路由数组的函数。
从一个文件中创建多个页面路由的过程。
定义动态生成的页面路由名称的值。
任务清单
相关资源
Tutorials如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论