跳到主要内容

自动生成侧边栏

道格龙(Docusaurus)可以根据你的文件系统结构自动创建一个侧边栏:每个文件夹创建一个侧边栏分类,每个文件创建一个文档链接。

type SidebarItemAutogenerated = {
type: 'autogenerated';
dirName: string; // 用于生成侧边栏切片的源文件夹(相对于 docs 目录)
};

道格龙(Docusaurus)可以从你的 docs 文件夹中生成一个完整的侧边栏:

sidebars.js
export default {
myAutogeneratedSidebar: [
{
type: 'autogenerated',
dirName: '.', // '.' 表示当前的 docs 文件夹
},
],
};

一个 autogenerated 项目会被道格龙(Docusaurus)转换成一个侧边栏切片(在分类简写中也讨论过):一个由 doccategory 类型的项目组成的列表。因此,你可以在一个侧边栏层级中,将来自多个目录的多个 autogenerated 项目与常规的侧边栏项目穿插拼接在一起。

一个实际示例子

考虑以下文件结构:

docs
├── api
│ ├── product1-api
│ │ └── api.md
│ └── product2-api
│ ├── basic-api.md
│ └── pro-api.md
├── intro.md
└── tutorials
├── advanced
│ ├── advanced1.md
│ ├── advanced2.md
│ └── read-more
│ ├── resource1.md
│ └── resource2.md
├── easy
│ ├── easy1.md
│ └── easy2.md
├── tutorial-end.md
├── tutorial-intro.md
└── tutorial-medium.md

并假设每个文档的 ID 就是其文件名。如果你定义一个自动生成的侧边栏,如下所示:

sidebars.js
export default {
mySidebar: [
'intro',
{
type: 'category',
label: '教程',
items: [
'tutorial-intro',
{
type: 'autogenerated',
dirName: 'tutorials/easy', // 从 docs/tutorials/easy 生成侧边栏切片
},
'tutorial-medium',
{
type: 'autogenerated',
dirName: 'tutorials/advanced', // 从 docs/tutorials/advanced 生成侧边栏切片
},
'tutorial-end',
],
},
{
type: 'autogenerated',
dirName: 'api', // 从 docs/api 生成侧边栏切片
},
{
type: 'category',
label: '社区',
items: ['team', 'chat'],
},
],
};

它将被解析为:

sidebars.js
export default {
mySidebar: [
'intro',
{
type: 'category',
label: '教程',
items: [
'tutorial-intro',
// docs/tutorials/easy 目录下的两个文件
'easy1',
'easy2',
'tutorial-medium',
// docs/tutorials/advanced 目录下的两个文件和一个文件夹
'advanced1',
'advanced2',
{
type: 'category',
label: 'read-more',
items: ['resource1', 'resource2'],
},
'tutorial-end',
],
},
// docs/api 目录下的两个文件夹
{
type: 'category',
label: 'product1-api',
items: ['api'],
},
{
type: 'category',
label: 'product2-api',
items: ['basic-api', 'pro-api'],
},
{
type: 'category',
label: '社区',
items: ['team', 'chat'],
},
],
};

请注意,自动生成的源目录本身并不会成为分类:只有它们包含的项目才会。这就是我们所说的"侧边栏切片"。

分类索引页约定

道格龙(Docusaurus)可以自动将一个分类链接到其索引文档。

分类索引文档是遵循以下任一命名约定的文档:

  • 名为 index(不区分大小写):docs/Guides/index.md
  • 名为 README(不区分大小写):docs/Guides/README.mdx
  • 与父文件夹同名:docs/Guides/Guides.md

这等同于使用一个带有文档链接的分类:

sidebars.js
export default {
docs: [
{
type: 'category',
label: '指南',
link: {type: 'doc', id: 'Guides/index'},
items: [],
},
],
};
提示

将你的介绍性文档命名为 README.md,可以使其在使用 GitHub 界面浏览文件夹时显示出来;而使用 index.md 则使其行为更符合 HTML 文件的服务方式。

提示

如果一个文件夹中只有一个索引页,它将被转换成一个链接而不是一个分类。这对于资源归类非常有用:

some-doc
├── index.md
├── img1.png
└── img2.png
自定义分类索引匹配

可以退出任何分类索引约定,或者定义更多的约定。你可以通过 sidebarItemsGenerator 回调注入你自己的 isCategoryIndex 匹配器。例如,你也可以选择 intro 作为另一个符合自动成为分类索引条件的文件名。

docusaurus.config.js
export default {
plugins: [
[
'@docusaurus/plugin-content-docs',
{
async sidebarItemsGenerator({
...args,
isCategoryIndex: defaultCategoryIndexMatcher, // 默认的匹配器实现,如下所示
defaultSidebarItemsGenerator,
}) {
return defaultSidebarItemsGenerator({
...args,
isCategoryIndex(doc) {
return (
// 除了默认的,也选择 intro.md
doc.fileName.toLowerCase() === 'intro' ||
defaultCategoryIndexMatcher(doc)
);
},
});
},
},
],
],
};

或者选择不使用任何分类索引约定。

docusaurus.config.js
export default {
plugins: [
[
'@docusaurus/plugin-content-docs',
{
async sidebarItemsGenerator({
...args,
isCategoryIndex: defaultCategoryIndexMatcher, // 默认的匹配器实现,如下所示
defaultSidebarItemsGenerator,
}) {
return defaultSidebarItemsGenerator({
...args,
isCategoryIndex() {
// 没有文档会被自动选为分类索引
return false;
},
});
},
},
],
],
};

isCategoryIndex 匹配器将被提供三个字段:

  • fileName:文件的名称,不含扩展名,大小写保留。
  • directories:从最低级到最高级的目录名称列表,相对于文档根目录。
  • extension:文件的扩展名,以“.”开头。

例如,对于一个位于 guides/sidebar/autogenerated.md 的文档文件,匹配器接收到的 属性(props) 是:

const props = {
fileName: 'autogenerated',
directories: ['sidebar', 'guides'],
extension: '.md',
};

默认的实现是:

function isCategoryIndex({fileName, directories}) {
const eligibleDocIndexNames = [
'index',
'readme',
directories[0].toLowerCase(),
];
return eligibleDocIndexNames.includes(fileName.toLowerCase());
}

自动生成侧边栏的元数据

对于手写的侧边栏定义,你需要通过 sidebars.js 为侧边栏项目提供元数据;对于自动生成的侧边栏,道格龙(Docusaurus)会从项目的相应文件中读取它们。此外,你可能需要调整每个项目的相对位置,因为默认情况下,侧边栏切片中的项目会按字母顺序(使用文件和文件夹名)生成。

文档项目元数据

labelclassNamecustomProps 属性在头部元数据中分别声明为 sidebar_labelsidebar_class_namesidebar_custom_props。位置可以通过 sidebar_position 头部元数据以同样的方式指定。

docs/tutorials/tutorial-easy.md
---
sidebar_position: 2
sidebar_label: 简单教程
sidebar_class_name: green
---

# 简单教程

这是简单教程!

分类项目元数据

在相应的文件夹中添加一个 _category_.json_category_.yml 文件。你可以指定任何分类元数据以及 position 元数据。如果分类有关联的文档,labelclassNamepositioncustomProps 将默认使用该文档的相应值。

docs/tutorials/_category_.json
{
"position": 2.5,
"label": "教程",
"collapsible": true,
"collapsed": false,
"className": "red",
"link": {
"type": "generated-index",
"title": "教程概览"
},
"customProps": {
"description": "这段描述可以在 swizzled 后的 DocCard 中使用"
}
}
信息

如果显式指定了 link,道格龙(Docusaurus)将不会应用任何默认约定

文档链接可以相对指定,例如,如果分类是由 guides 目录生成的,"link": {"type": "doc", "id": "intro"} 将被解析为 ID guides/intro,仅在找不到前一个 ID 的文档时才会回退到 intro

你也可以使用 link: null 来退出默认约定,不生成任何分类索引页。

信息

位置元数据仅在侧边栏切片内部使用:道格龙(Docusaurus)不会重新排序你侧边栏的其他项目。

使用数字前缀

一种简单的排序自动生成侧边栏的方法是给文档和文件夹加上数字前缀,这也使得它们在文件系统中按文件名排序时以相同的顺序列出:

docs
├── 01-Intro.md
├── 02-Tutorial Easy
│ ├── 01-First Part.md
│ ├── 02-Second Part.md
│ └── 03-End.md
├── 03-Tutorial Advanced
│ ├── 01-First Part.md
│ ├── 02-Second Part.md
│ ├── 03-Third Part.md
│ └── 04-End.md
└── 04-End.md

为了更容易采用,道格龙(Docusaurus)支持多种数字前缀模式

默认情况下,道格龙(Docusaurus)会从文档的 ID、标题、标签和 URL 路径中移除数字前缀

注意

推荐优先使用附加元数据

更新数字前缀可能很麻烦,因为它可能需要更新多个现有的 Markdown 链接

docs/02-Tutorial Easy/01-First Part.md
- 查看 [教程结束](../04-End.mdx);
+ 查看 [教程结束](../05-End.mdx);

自定义侧边栏项目生成器

你可以在文档插件(或预设)的配置中提供一个自定义的 sidebarItemsGenerator 函数:

docusaurus.config.js
export default {
plugins: [
[
'@docusaurus/plugin-content-docs',
{
async sidebarItemsGenerator({
defaultSidebarItemsGenerator,
numberPrefixParser,
item,
version,
docs,
categoriesMetadata,
isCategoryIndex,
}) {
// 示例:返回一个硬编码的静态侧边栏项目列表
return [
{type: 'doc', id: 'doc1'},
{type: 'doc', id: 'doc2'},
];
},
},
],
],
};
提示

复用并增强默认生成器,而不是从头开始编写一个生成器:我们提供的默认生成器有 250 行长。

根据你的使用场景添加、更新、过滤、重新排序侧边栏项目:

docusaurus.config.js
// 反转侧边栏项目的顺序(包括嵌套的分类项目)
function reverseSidebarItems(items) {
// 反转分类中的项目
const result = items.map((item) => {
if (item.type === 'category') {
return {...item, items: reverseSidebarItems(item.items)};
}
return item;
});
// 反转当前层级的项目
result.reverse();
return result;
}

export default {
plugins: [
[
'@docusaurus/plugin-content-docs',
{
async sidebarItemsGenerator({defaultSidebarItemsGenerator, ...args}) {
const sidebarItems = await defaultSidebarItemsGenerator(args);
return reverseSidebarItems(sidebarItems);
},
},
],
],
};