EmDash 提供在 Astro 页面与组件中获取内容的查询函数,遵循 Astro 的 live content collections 模式,返回带错误处理的结构化结果。
查询函数
EmDash 导出两个主要查询函数:
| 函数 | 作用 | 返回值 |
|---|---|---|
getEmDashCollection | 获取某内容类型的全部条目 | { entries, error } |
getEmDashEntry | 按 ID 或 slug 获取单条 | { entry, error, isPreview } |
从 emdash 导入:
import { getEmDashCollection, getEmDashEntry } from "emdash";
获取全部条目
使用 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>
按语言区域筛选
启用 i18n 后,可用 locale 获取指定语言内容:
const { entries: frenchPosts } = await getEmDashCollection("posts", {
locale: "fr",
status: "published",
});
const { entries: localizedPosts } = await getEmDashCollection("posts", {
locale: Astro.currentLocale,
status: "published",
});
单条查询将 locale 作为第三个参数传入:
const { entry: post } = await getEmDashEntry("posts", "my-post", {
locale: Astro.currentLocale,
});
省略 locale 时默认使用当前请求的语言区域;若无翻译则走 回退链。
按状态筛选
仅已发布或仅草稿:
const { entries: published } = await getEmDashCollection("posts", {
status: "published",
});
const { entries: drafts } = await getEmDashCollection("posts", {
status: "draft",
});
限制条数
const { entries: recentPosts } = await getEmDashCollection("posts", {
status: "published",
limit: 5,
});
按分类体系筛选
按分类、标签或自定义术语:
const { entries: newsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { category: "news" },
});
const { entries: jsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { tag: "javascript" },
});
const { entries: featuredNews } = await getEmDashCollection("posts", {
status: "published",
where: { category: ["news", "featured"] },
});
对同一分类字段提供多个值时,where 使用 OR 逻辑。
错误处理
在需要可靠性的场景始终检查 error:
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) {
console.error("Failed to load posts:", error);
return new Response("Server error", { status: 500 });
}
获取单条条目
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>
返回类型
interface EntryResult<T> {
entry: ContentEntry<T> | null;
error?: Error;
isPreview: boolean;
}
interface ContentEntry<T> {
id: string;
data: T;
edit: EditProxy;
}
预览模式
中间件会校验 _preview;查询函数无需额外参数即可返回草稿:
---
import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;
const { 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">
预览中。此内容尚未发布。
</div>
)}
<article>
<h1>{entry.data.title}</h1>
<PortableText value={entry.data.content} />
</article>
可视化编辑
<article {...entry.edit}>
<h1 {...entry.edit.title}>{entry.data.title}</h1>
<div {...entry.edit.content}>
<PortableText value={entry.data.content} />
</div>
</article>
排序
getEmDashCollection 不保证顺序,请在模板中排序:
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
});
const sorted = posts.sort(
(a, b) => (b.data.publishedAt?.getTime() ?? 0) - (a.data.publishedAt?.getTime() ?? 0),
);
posts.sort((a, b) => a.data.title.localeCompare(b.data.title));
posts.sort((a, b) => (a.data.order ?? 0) - (b.data.order ?? 0));
posts.sort(() => Math.random() - 0.5);
TypeScript
npx emdash types
import { getEmDashCollection, getEmDashEntry } from "emdash";
import type { Post } from "../.emdash/types";
const { entries: posts } = await getEmDashCollection<Post>("posts");
const { entry: post } = await getEmDashEntry<Post>("posts", "my-post");
静态与服务器渲染
静态(预渲染)
---
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 });
}
---
性能
缓存
---
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
});
Astro.response.headers.set("Cache-Control", "public, max-age=300");
---
避免重复查询
---
import { getEmDashCollection } from "emdash";
import PostList from "../components/PostList.astro";
import Sidebar from "../components/Sidebar.astro";
const { 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} />
下一步
- Create a Blog — 搭建完整博客
- Taxonomies — 按分类与标签筛选
- Working with Content — 后台 CRUD
- Internationalization — 多语言内容