查询内容
EmDash 提供了查询函数,用于在您的 Astro 页面和组件中检索内容。这些函数遵循 Astro 的 实时内容集合 模式,返回带有错误处理的结构化结果。
EmDash 导出两个主要的查询函数:
| 函数 | 用途 | 返回类型 |
|---|---|---|
getEmDashCollection | 检索某个内容类型的所有条目 | { entries, error } |
getEmDashEntry | 通过 ID 或 slug 检索单个条目 | { entry, error, isPreview } |
从 emdash 导入它们:
import { getEmDashCollection, getEmDashEntry } from "emdash";获取所有条目
Section titled “获取所有条目”使用 getEmDashCollection 检索某个内容类型的所有条目:
---import { getEmDashCollection } from "emdash";
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) { console.error("Failed to load posts:", error);}---
<ul> {posts.map((post) => ( <li>{post.data.title}</li> ))}</ul>按语言区域过滤
Section titled “按语言区域过滤”当 启用了 i18n 时,按语言区域过滤以检索特定语言的内容:
// French postsconst { entries: frenchPosts } = await getEmDashCollection("posts", { locale: "fr", status: "published",});
// Use the current request localeconst { entries: localizedPosts } = await getEmDashCollection("posts", { locale: Astro.currentLocale, status: "published",});对于单个条目,将 locale 作为第三个参数传递:
const { entry: post } = await getEmDashEntry("posts", "my-post", { locale: Astro.currentLocale,});当省略 locale 时,它默认为请求的当前语言区域。如果请求的语言区域没有翻译,则会遵循 回退链。
仅检索已发布或草稿内容:
// Only published postsconst { entries: published } = await getEmDashCollection("posts", { status: "published",});
// Only draftsconst { entries: drafts } = await getEmDashCollection("posts", { status: "draft",});限制结果数量
Section titled “限制结果数量”限制返回的条目数量:
// Get the 5 most recent postsconst { entries: recentPosts } = await getEmDashCollection("posts", { status: "published", limit: 5,});按分类法过滤
Section titled “按分类法过滤”按类别、标签或自定义分类法术语过滤条目:
// Posts in the "news" categoryconst { entries: newsPosts } = await getEmDashCollection("posts", { status: "published", where: { category: "news" },});
// Posts with the "javascript" tagconst { entries: jsPosts } = await getEmDashCollection("posts", { status: "published", where: { tag: "javascript" },});
// Posts matching any of multiple termsconst { entries: featuredNews } = await getEmDashCollection("posts", { status: "published", where: { category: ["news", "featured"] },});当为单个分类法提供多个值时,where 过滤器使用 OR 逻辑。
当可靠性很重要时,请务必检查错误:
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) { // Log and handle gracefully console.error("Failed to load posts:", error); return new Response("Server error", { status: 500 });}获取单个条目
Section titled “获取单个条目”使用 getEmDashEntry 通过其 ID 或 slug 检索一个条目:
---import { getEmDashEntry } from "emdash";import { PortableText } from "emdash/ui";
const { slug } = Astro.params;const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) { return new Response("Server error", { status: 500 });}
if (!post) { return Astro.redirect("/404");}---
<article> <h1>{post.data.title}</h1> <PortableText value={post.data.content} /></article>条目返回类型
Section titled “条目返回类型”getEmDashEntry 返回一个结果对象:
interface EntryResult<T> { entry: ContentEntry<T> | null; // null if not found error?: Error; // Only set for actual errors (not "not found") isPreview: boolean; // true if viewing preview/draft content}
interface ContentEntry<T> { id: string; data: T; edit: EditProxy; // Visual editing annotations}entry 内的 data 对象包含为该内容类型定义的所有字段。edit 代理提供可视化编辑注解(见下文)。
EmDash 通过中间件自动处理预览。当 URL 包含有效的 _preview 令牌时,中间件会验证它并设置请求上下文。然后,您的查询函数无需任何特殊参数即可提供草稿内容:
---import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;
// No special preview handling needed — middleware does it automaticallyconst { entry, isPreview, error } = await getEmDashEntry("posts", slug);
if (error) { return new Response("Server error", { status: 500 });}
if (!entry) { return Astro.redirect("/404");}---
{isPreview && ( <div class="preview-banner"> Viewing preview. This content is not published. </div>)}
<article> <h1>{entry.data.title}</h1> <PortableText value={entry.data.content} /></article>查询函数返回的每个条目都包含一个 edit 代理,用于注解您的模板。将其展开到元素上,以便为经过身份验证的编辑者启用内联编辑:
<article {...entry.edit}> <h1 {...entry.edit.title}>{entry.data.title}</h1> <div {...entry.edit.content}> <PortableText value={entry.data.content} /> </div></article>在编辑模式下,{...entry.edit.title} 会生成一个 data-emdash-ref 属性,可视化编辑工具栏使用该属性来启用内联编辑。在生产环境中,代理展开不会产生任何输出——零运行时成本。
getEmDashCollection 不保证排序顺序。在您的模板中对结果进行排序:
const { entries: posts } = await getEmDashCollection("posts", { status: "published",});
// Sort by publication date, newest firstconst sorted = posts.sort( (a, b) => (b.data.publishedAt?.getTime() ?? 0) - (a.data.publishedAt?.getTime() ?? 0),);常见排序模式
Section titled “常见排序模式”// Alphabetical by titleposts.sort((a, b) => a.data.title.localeCompare(b.data.title));
// By custom order fieldposts.sort((a, b) => (a.data.order ?? 0) - (b.data.order ?? 0));
// Random orderposts.sort(() => Math.random() - 0.5);TypeScript 类型
Section titled “TypeScript 类型”为您的集合生成 TypeScript 类型:
npx emdash types这将创建 .emdash/types.ts,其中包含每个集合的接口。使用它们以获得类型安全:
import { getEmDashCollection, getEmDashEntry } from "emdash";import type { Post } from "../.emdash/types";
// Type-safe collection queryconst { entries: posts } = await getEmDashCollection<Post>("posts");// posts is ContentEntry<Post>[]
// Type-safe entry queryconst { entry: post } = await getEmDashEntry<Post>("posts", "my-post");// post is ContentEntry<Post> | null静态渲染与服务器渲染
Section titled “静态渲染与服务器渲染”EmDash 内容适用于静态渲染和服务器渲染的页面。
静态(预渲染)
Section titled “静态(预渲染)”对于静态页面,使用 getStaticPaths 在构建时生成路由:
---import { getEmDashCollection, getEmDashEntry } from "emdash";
export async function getStaticPaths() { const { entries: posts } = await getEmDashCollection("posts", { status: "published", });
return posts.map((post) => ({ params: { slug: post.data.slug }, }));}
const { slug } = Astro.params;const { entry: post } = await getEmDashEntry("posts", slug);---对于服务器渲染的页面,直接查询内容:
---export const prerender = false;
import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;const { entry: post, error } = await getEmDashEntry("posts", slug);
if (error) { return new Response("Server error", { status: 500 });}
if (!post) { return new Response(null, { status: 404 });}---EmDash 使用 Astro 的实时内容集合,它会自动处理缓存。对于服务器渲染的页面,请考虑添加 HTTP 缓存头:
---const { entries: posts } = await getEmDashCollection("posts", { status: "published",});
// Cache for 5 minutesAstro.response.headers.set("Cache-Control", "public, max-age=300");---避免冗余查询
Section titled “避免冗余查询”查询一次并将数据传递给组件:
---import { getEmDashCollection } from "emdash";import PostList from "../components/PostList.astro";import Sidebar from "../components/Sidebar.astro";
// Query onceconst { entries: posts } = await getEmDashCollection("posts", { status: "published",});
const featured = posts.filter((p) => p.data.featured);const recent = posts.slice(0, 5);---
<PostList posts={featured} /><Sidebar posts={recent} />