分类法是用于组织内容的分类系统。EmDash 包含内置的分类和标签,并支持自定义分类法以满足专业化的分类需求。
内置分类法
EmDash 提供两种默认分类法:
| 分类法 | 类型 | 描述 |
|---|---|---|
| 分类 | 层级型 | 具有父子关系的嵌套分类 |
| 标签 | 扁平型 | 无层级的简单标签 |
两者默认可用于文章集合。
管理术语
创建术语
管理面板
-
前往分类法页面(例如
/_emdash/admin/taxonomies/category) -
在新增表单中输入术语名称
-
可选设置:
- Slug - URL 标识符(从名称自动生成)
- 父级 - 用于层级型分类法
- 描述 - 术语描述
-
点击添加
内容编辑器
-
在编辑器中打开一个内容条目
-
在侧边栏找到分类法面板
-
对于分类,勾选适用术语的复选框,或点击 + 新增
-
对于标签,输入用逗号分隔的标签名称
-
保存内容
API
以下请求在 category 分类法中创建一个术语:
POST /_emdash/api/taxonomies/category/terms
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN
{
"slug": "tutorials",
"label": "教程",
"parentId": "term_abc",
"description": "操作指南和教程"
} 编辑术语
-
前往分类法术语页面
-
点击术语旁边的编辑
-
更新名称、slug、父级或描述
-
点击保存
删除术语
-
前往分类法术语页面
-
点击术语旁边的删除
-
确认删除
查询分类法
EmDash 提供用于查询分类法术语和按术语过滤内容的函数。
获取所有术语
检索分类法的所有术语:
import { getTaxonomyTerms } from "emdash";
// 获取所有分类(返回树形结构)
const categories = await getTaxonomyTerms("category");
// 获取所有标签(返回扁平列表)
const tags = await getTaxonomyTerms("tag");
对于层级型分类法,术语包含 children 数组:
interface TaxonomyTerm {
id: string;
name: string; // 分类法名称 ("category")
slug: string; // 术语 slug ("news")
label: string; // 显示标签 ("News")
parentId?: string;
description?: string;
children: TaxonomyTerm[];
count?: number; // 使用此术语的条目数
}
计算 count 会聚合分类法集合中的每个内容-术语分配,这是调用中最昂贵的部分。如果你只需要标签和 slug,可以跳过——count 将从返回的术语中省略:
const tags = await getTaxonomyTerms("tag", { includeCounts: false });
获取单个术语
以下示例按分类法和 slug 获取术语:
import { getTerm } from "emdash";
const category = await getTerm("category", "news");
// 返回 TaxonomyTerm 或 null
获取条目的术语
以下示例检索分配给单个条目的分类和标签:
import { getEntryTerms } from "emdash";
// 获取文章的所有分类
const categories = await getEntryTerms("posts", "post-123", "category");
// 获取文章的所有标签
const tags = await getEntryTerms("posts", "post-123", "tag");
按术语过滤内容
使用 getEmDashCollection 配合 where 过滤器:
import { getEmDashCollection } from "emdash";
// "news" 分类的文章
const { entries: newsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { category: "news" },
});
// "javascript" 标签的文章
const { entries: jsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { tag: "javascript" },
});
或使用便捷函数:
import { getEntriesByTerm } from "emdash";
const newsPosts = await getEntriesByTerm("posts", "category", "news");
构建分类法页面
分类归档
创建一个列出某分类文章的页面:
---
import { getTaxonomyTerms, getTerm, getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";
export async function getStaticPaths() {
const categories = await getTaxonomyTerms("category");
function flatten(terms) {
return terms.flatMap((term) => [term, ...flatten(term.children)]);
}
return flatten(categories).map((cat) => ({
params: { slug: cat.slug },
props: { category: cat },
}));
}
const { category } = Astro.props;
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
where: { category: category.slug },
});
---
<Base title={category.label}>
<h1>{category.label}</h1>
{category.description && <p>{category.description}</p>}
<p>{category.count} 篇文章</p>
<ul>
{posts.map((post) => (
<li>
<a href={`/blog/${post.data.slug}`}>{post.data.title}</a>
</li>
))}
</ul>
</Base>
标签归档
创建一个列出某标签文章的页面:
---
import { getTaxonomyTerms, getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";
export async function getStaticPaths() {
const tags = await getTaxonomyTerms("tag");
return tags.map((tag) => ({
params: { slug: tag.slug },
props: { tag },
}));
}
const { tag } = Astro.props;
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
where: { tag: tag.slug },
});
---
<Base title={`标签"${tag.label}"的文章`}>
<h1>#{tag.label}</h1>
<ul>
{posts.map((post) => (
<li>
<a href={`/blog/${post.data.slug}`}>{post.data.title}</a>
</li>
))}
</ul>
</Base>
分类列表组件
显示带有文章计数的分类列表:
---
import { getTaxonomyTerms } from "emdash";
const categories = await getTaxonomyTerms("category");
---
<nav class="category-list">
<h3>分类</h3>
<ul>
{categories.map((cat) => (
<li>
<a href={`/category/${cat.slug}`}>
{cat.label} ({cat.count})
</a>
{cat.children.length > 0 && (
<ul>
{cat.children.map((child) => (
<li>
<a href={`/category/${child.slug}`}>
{child.label} ({child.count})
</a>
</li>
))}
</ul>
)}
</li>
))}
</ul>
</nav>
标签云
根据使用频率显示不同大小的标签:
---
import { getTaxonomyTerms } from "emdash";
const tags = await getTaxonomyTerms("tag");
const counts = tags.map((t) => t.count ?? 0);
const maxCount = Math.max(...counts, 1);
const minSize = 0.8;
const maxSize = 2;
function getSize(count: number) {
const ratio = count / maxCount;
return minSize + ratio * (maxSize - minSize);
}
---
<div class="tag-cloud">
{tags.map((tag) => (
<a
href={`/tag/${tag.slug}`}
style={`font-size: ${getSize(tag.count ?? 0)}rem`}
>
{tag.label}
</a>
))}
</div>
在内容上显示术语
在文章上显示分类和标签:
---
import { getEntryTerms } from "emdash";
interface Props {
collection: string;
entryId: string;
}
const { collection, entryId } = Astro.props;
const categories = await getEntryTerms(collection, entryId, "category");
const tags = await getEntryTerms(collection, entryId, "tag");
---
<div class="post-terms">
{categories.length > 0 && (
<div class="categories">
<span>发布于:</span>
{categories.map((cat, i) => (
<>
{i > 0 && ", "}
<a href={`/category/${cat.slug}`}>{cat.label}</a>
</>
))}
</div>
)}
{tags.length > 0 && (
<div class="tags">
{tags.map((tag) => (
<a href={`/tag/${tag.slug}`} class="tag">
#{tag.label}
</a>
))}
</div>
)}
</div>
自定义分类法
为专业化需求创建超越分类和标签的分类法。
创建自定义分类法
使用管理 API 创建分类法:
POST /_emdash/api/taxonomies
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN
{
"name": "genre",
"label": "类型",
"labelSingular": "类型",
"hierarchical": true,
"collections": ["books", "movies"]
}
使用自定义分类法
以与内置分类法相同的方式查询和显示自定义分类法:
import { getTaxonomyTerms, getEmDashCollection } from "emdash";
// 获取所有类型
const genres = await getTaxonomyTerms("genre");
// 获取某类型的书籍
const { entries: sciFiBooks } = await getEmDashCollection("books", {
where: { genre: "science-fiction" },
});
分配到集合
分类法指定它们适用于哪些集合:
{
"name": "difficulty",
"label": "难度级别",
"hierarchical": false,
"collections": ["recipes", "tutorials"]
}
分类法 API 参考
REST 端点
| 端点 | 方法 | 描述 |
|---|---|---|
/_emdash/api/taxonomies | GET | 列出分类法定义 |
/_emdash/api/taxonomies | POST | 创建分类法 |
/_emdash/api/taxonomies/:name/terms | GET | 列出术语 |
/_emdash/api/taxonomies/:name/terms | POST | 创建术语 |
/_emdash/api/taxonomies/:name/terms/:slug | GET | 获取术语 |
/_emdash/api/taxonomies/:name/terms/:slug | PUT | 更新术语 |
/_emdash/api/taxonomies/:name/terms/:slug | DELETE | 删除术语 |
为内容分配术语
以下请求为文章分配分类术语:
POST /_emdash/api/content/posts/post-123/terms/category
Content-Type: application/json
Authorization: Bearer YOUR_API_TOKEN
{
"termIds": ["term_news", "term_featured"]
}