跳到主要内容
版本:Canary 🚧

搅拌

在本节中,我们将介绍如何在 Docusaurus 中定制布局。

Déja vu...?

这一节类似于样式和布局,但这一次,我们将自定义 React 组件本身,而不是它们的样子。我们将讨论 Docusaurus 中的一个核心概念:swizzling,它允许更深层次的站点自定义

在实践中,swizzling 允许用你自己的实现交换主题组件,它有两种模式:

  • 弹出: 创建原始主题组件的副本,您可以完全自定义
  • 包装: 在原始主题组件周围创建一个包装器,您可以增强
为什么叫swizzling?

这个名字来源于 Objective-C 和 Swift-UI: method swizzling是改变现有选择器(方法)实现的过程。

对于 Docusaurus,组件混合意味着提供一个替代组件,该组件优先于主题提供的组件。

你可以把它想象成 React 组件的Monkey patch,使你能够覆盖默认实现。盖茨比有一个类似的概念,叫做主题阴影

为了更深入地理解这一点,您必须了解主题组件是如何解析的

Swizzling 过程

概述

Docusaurus 提供了一个方便的交互式 CLI来混合组件。一般只需要记住以下命令:

npm run swizzle

它将在你的src/theme目录下生成一个新组件,看起来应该像下面这个例子:

src/theme/SomeComponent.js
import React from "react";

export default function SomeComponent(props) {
// You can fully customize this implementation
// including changing the JSX, CSS and React hooks
return (
<div className="some-class">
<h1>Some Component</h1>
<p>Some component implementation details</p>
</div>
);
}

要获得 swizzle 可用的所有主题和组件的概述,请运行:

npm run swizzle -- --list

使用--help查看所有可用的 CLI 选项,或参考swizzle CLI 文档

备注

在搅拌组件后,重新启动开发服务器,以便 Docusaurus 了解新组件。

我更喜欢安全起见

一定要了解哪些组件可以安全搅拌。有些组件是主题的内部实现细节。

信息

docusaurus swizzle只是一种自动的方法来帮助你搅拌组件。你也可以手动创建src/theme/SomeComponent.js文件,Docusaurus 会解析。这个命令背后没有内在的魔法!

Ejecting

弹出主题组件是创建原始主题组件副本的过程,您可以对其进行完全的自定义和覆盖。

要弹出主题组件,可以交互式地使用 swizzle CLI,或者使用--eject选项:

npm run swizzle [theme name] [component name] -- --eject

一个例子:

npm run swizzle @docusaurus/theme-classic Footer -- --eject

这将把当前<Footer />组件的实现复制到你网站的src/theme目录。Docusaurus 现在将使用这个<Footer />组件副本而不是原始的。现在可以完全重新实现<Footer />组件了。

src/theme/Footer/index.js
import React from "react";

export default function Footer(props) {
return (
<footer>
<h1>This is my custom site footer</h1>
<p>And it is very different from the original</p>
</footer>
);
}
警告

弹出一个不安全的组件有时会导致复制大量的内部代码,现在你必须自己维护这些代码。这可能会使 Docusaurus 升级变得更加困难,因为如果收到的属性或使用的内部主题 api 发生了变化,则需要迁移自定义。

尽可能使用wrapped: 需要维护的代码量更少。

Re-swizzling

要在 Docusaurus 升级后保持被弹出的组件是最新的,请重新运行 eject 命令并将更改与git diff进行比较。还建议在文件的顶部写一个简短的注释,解释所做的更改,以便在重新弹出后更容易地重新应用更改。

包装

包装主题组件是在原始主题组件周围创建包装器的过程,您可以对其进行增强。

要包装主题组件,可以交互式地使用 swizzle CLI,或者使用--wrap选项:

npm run swizzle [theme name] [component name] -- --wrap

一个例子:

npm run swizzle @docusaurus/theme-classic Footer -- --wrap

这将在站点的src/theme目录下创建一个包装器。Docusaurus 现在将使用<FooterWrapper>组件而不是原来的组件。现在可以围绕原始组件添加自定义。

src/theme/Footer/index.js
import React from "react";
import Footer from "@theme-original/Footer";

export default function FooterWrapper(props) {
return (
<>
<section>
<h2>Extra section</h2>
<p>This is an extra section that appears above the original footer</p>
</section>
<Footer {...props} />
</>
);
}
这个@theme-original是什么?

Docusaurus 使用主题别名来解析要使用的主题组件。新创建的包装器使用@theme/SomeComponent别名。@theme-original/SomeComponent允许导入包装器隐藏的原始组件,而不会在包装器导入自身时创建无限导入循环。

提示

包装主题是在现有主题周围添加额外组件的好方法,而无需弹出它。 例如,你可以很容易地在每篇博客文章下添加一个自定义评论系统:

src/theme/BlogPostItem.js
import React from "react";
import BlogPostItem from "@theme-original/BlogPostItem";
import MyCustomCommentSystem from "@site/src/MyCustomCommentSystem";

export default function BlogPostItemWrapper(props) {
return (
<>
<BlogPostItem {...props} />
<MyCustomCommentSystem />
</>
);
}

什么是安全的搅拌?

权力越大,责任越大

一些主题组件是主题的内部实现细节。Docusaurus 可以让你搅拌它们,但这可能有风险。

为什么有风险?

主题作者(包括我们)可能需要随时更新他们的主题:更改组件属性、名称、文件系统位置、类型……例如,考虑一个组件,它接收了两个属性nameage,但在重构之后,它现在接收了一个带有上述两个属性的person属性。你的组件,仍然需要这两个属性,将渲染为undefined

此外,内部组件可能会消失。如果一个组件被命名为Sidebar,后来它被重命名为DocSidebar,那么你的 swizzzed 组件将被完全忽略。

标记为不安全的主题组件可能在主题次要版本之间以向后不兼容的方式更改。 升级主题(或 Docusaurus)时,您的自定义可能行为出乎意料,甚至可能破坏您的网站

对于每个主题组件,swizzle CLI 将显示由主题作者声明的 3 个不同的安全级别:

  • Safe: 这个组件是安全的,它的公共 API 被认为是稳定的,在主题主版本中不应该发生破坏性的变化
  • Unsafe: 该组件是一个主题实现细节,不安全,并且可能在主题小版本中发生破坏性更改
  • Forbidden: swizzle CLI 将阻止您对该组件进行搅拌,因为它根本不是为搅拌而设计的
备注

有些组件可以安全包装,但不能安全弹出。

信息

不要太害怕使用不安全的组件:只要记住可能会发生破坏性的更改,并且您可能需要在小版本升级时手动升级您的自定义。

报告您的用例

如果你有一个强大的用例搅拌一个不安全的组件,请在这里报告,我们将共同努力找到一个解决方案,使其安全。

我应该搅拌哪个组件?

为了达到预期的效果,您应该准确地搅拌哪个组件并不总是很清楚。@docusaurus/theme-classic提供了大多数主题组件,大约有100 个组件!

提示

打印所有@docusaurus/theme-classic组件的概述:

npm run swizzle @docusaurus/theme-classic -- --list

您可以按照以下步骤找到要搅拌的适当组件:

  1. 组件描述. 有些组件提供简短的描述,这是找到正确组件的好方法。
  2. 组件名称. 官方主题组件在语义上命名,因此您应该能够从名称推断其功能。swizzle CLI 允许您输入组件名称的一部分,以缩小可用选项的范围。例如,如果你运行yarn swizzle @docusaurus/theme-classic,然后输入Doc,只会列出与 Doc 相关的组件。
  3. 从更高级的组件开始. 组件形成一个树,其中一些组件导入其他组件。每条路由都将与该路由将呈现的一个顶级组件相关联(它们中的大多数列在内容插件中的路由中)。例如,所有的博客文章页面都有@theme/BlogPostPage作为最上面的组件。您可以从混合这个组件开始,然后沿着组件树向下查找呈现您所要的内容的组件。不要忘记在找到正确的文件后通过删除文件来清除其余的文件,这样就不会维护太多的组件。
  4. 阅读主题源代码 并明智地使用搜索.
只是问问!

如果你仍然不知道应该混合哪个组件来达到预期的效果,你可以在我们的支持渠道中寻求帮助。

我们也想更好地了解你最花哨的定制用例,所以请报告他们

我需要搅拌吗?

Swizzling 最终意味着你必须维护一些与 Docusaurus 内部 api 交互的额外 React 代码。如果可以,在定制您的网站时考虑以下选择:

  1. 使用 CSS. CSS 规则和选择器通常可以帮助您实现相当程度的自定义。参考样式和布局了解更多细节。
  2. 使用翻译. 这可能听起来令人惊讶,但翻译最终只是自定义文本标签的一种方式。例如,如果你网站的默认语言是en,你仍然可以运行yarn write-translations -l en并编辑发出的code.json。请参阅i18n 教程了解更多细节。
提示

越小越好. 如果混合是不可避免的,最好只混合相关的部分,自己维护尽可能少的代码。混合一个小组件通常意味着在升级过程中破坏更改的风险更小。

ejecting相比,Wrapping也是一个安全得多的选择。

<Root>包装你的站点

<Root>组件呈现在 React 树的最顶层,在主题<Layout>之上,并且永远不会卸载。 它是添加不应该跨导航(用户身份验证状态、购物车状态……)重新初始化的有状态逻辑的理想场所。

手动src/theme/Root.js创建一个文件:

src/theme/Root.js
import React from "react";

// Default implementation, that you can customize
export default function Root({ children }) {
return <>{children}</>;
}
提示

使用这个组件来呈现 React 上下文提供程序。