主题

优质
小牛编辑
129浏览
2023-12-01

像插件一样,主题(themes)旨在为你的 Docusaurus 网站添加功能。根据经验,主题主要关注点是客户端,而插件则更侧重于服务器端的功能。主题还被设计为可被其它主题覆盖。

可用的主题

请见 官方主题列表

使用主题

要使用主题,请在 docusaurus.config.js 配置文件中指定主题即可。也可以使用多个主题:

docusaurus.config.js
module.exports = {
  // ...
  themes: ['@docusaurus/theme-classic', '@docusaurus/theme-live-codeblock'],
};

主题组件

在大多数情况下,主题用于提供一组 React 组件,例如导航栏、布局、页脚。

用户可以通过使用 @theme 形式的 webpack 别名来导入(import)这些组件并在代码中使用它们:

import Navbar from '@theme/Navbar';

@theme 别名可以引用多个目录,并分为以下优先级:

  1. 用户的 website/src/theme 目录,这是具有较高优先级的特殊目录。
  2. Docusaurus 主题包的 theme 目录。
  3. Docusaurus core 提供的后备组件(通常不需要)。

假设有以下结构:

website
├── node_modules
│   └── docusaurus-theme
│       └── theme
│           └── Navbar.js
└── src
    └── theme
        └── Navbar.js

每当导入 @theme/Navbar 时,website/src/theme/Navbar.js 被优先使用。此行为称为组件 swizzling。在 iOS 中,swizzling 方法能够更改现有 selector(方法)的实现方式。在网站开发的语境中,组件级的 swizzling 意味着提供了一个替代组件,该组件优先于主题所提供的组件。

主题提供了用于内容呈现的 UI 组件。 大多数内容处理相关的插件需要与主题配合才能真正有用。UI 是与数据架构分离的一层,因此可以轻松地将主题替换为其他设计(例如 Bootstrap)。

例如,Docusaurus 博客由博客插件和博客主题组成。

docusaurus.config.js
{
  theme: ['theme-blog'],
  plugins: ['plugin-content-blog'],
}

如果您想使用 Bootstrap 样式,可以将主题替换为 theme-blog-bootstrap(一个虚构的不存在主题):

docusaurus.config.js
{
  theme: ['theme-blog-bootstrap'],
  plugins: ['plugin-content-blog'],
}

Wrapping your site with <Root>

A <Root> theme component is rendered at the very top of your Docusaurus site.

It allows you to wrap your site with additional logic, by creating a file at src/theme/Root.js:

website/src/theme/Root.js
import React from 'react';
// Default implementation, that you can customize
function Root({children}) {
  return <>{children}</>;
}
export default Root;

This component is applied above the router and the theme <Layout>, and will never unmount.

tip

Use this component to render React Context providers and global stateful logic.

Swizzling 主题组件

caution

在 Docusaurus 2 的 beta 阶段,我们不鼓励对组件的 swizzling。主题组件的 API 未来可能会改变并且不向后兼容。如果可能的话,请尽量使用默认主题。

Docusaurus 的主题组件被设计为可更换的。为了让你替换主题组件能够更容易,我们为你创建了 swizzle 命令。

要替换主题的组件,请在你的文档站点中运行以下命令:

  • npm
  • Yarn
npm run swizzle <theme name> [component name]
yarn run swizzle <theme name> [component name]

例如,要为你的站点替换 @docusaurus/theme-classic 主题中的 <Footer /> 组件,请运行:

  • npm
  • Yarn
npm run swizzle @docusaurus/theme-classic Footer
yarn run swizzle @docusaurus/theme-classic Footer

这会将当前主题所使用的 <Footer /> 组件复制到站点根目录下的 src/theme/Footer目录中,Docusaurus 将在该目录中查找被替换的组件。然后,Docusaurus 将使用被替换的组件代替主题中的原始组件。

尽管我们强烈建议不要替换(swizzling)所有组件,但是如果您希望这样做,请运行:

  • npm
  • Yarn
npm run swizzle @docusaurus/theme-classic
yarn run swizzle @docusaurus/theme-classic

注意:你需要重新启动 webpack 开发服务器,以使 Docusaurus 知道新组件。

Wrapping theme components

Sometimes, you just want to wrap an existing theme component with additional logic, and it can be a pain to have to maintain an almost duplicate copy of the original theme component.

In such case, you should swizzle the component you want to wrap, but import the original theme component in your customized version to wrap it.

For site owners

The @theme-original alias allows you to import the original theme component.

Here is an example to display some text just above the footer, with minimal code duplication.

src/theme/Footer.js
// Note: importing from "@theme/Footer" would fail due to the file importing itself
import OriginalFooter from '@theme-original/Footer';
import React from 'react';
export default function Footer(props) {
  return (
    <>
      <div>Before footer</div>
      <OriginalFooter {...props} />
    </>
  );
}

For plugin authors

One theme can wrap a component from another theme, by importing the component from the initial theme, using the @theme-init import.

Here's an example of using this feature to enhance the default theme CodeBlock component with a react-live playground feature.

import InitialCodeBlock from '@theme-init/CodeBlock';
import React from 'react';
export default function CodeBlock(props) {
  return props.live ? (
    <ReactLivePlayground {...props} />
  ) : (
    <InitialCodeBlock {...props} />
  );
}

Check the code of docusaurus-theme-live-codeblock for details.

caution

Unless you want publish to npm a "theme enhancer" (like docusaurus-theme-live-codeblock), you likely don't need @theme-init.

主题设计

尽管主题与插件共享完全相同的生命周期方法,但是它们的实现看起来与基于主题设计目标的插件的实现有很大不同。

主题旨在完成 Docusaurus 网站的构建,并为你的网站提供所需的组件、插件和主题本身。因此,一个典型的主题实现看起来像是一个 src/index.js 文件,并将其连接到生命周期方法中。他们很可能不会使用插件所使用的 loadContent。主题通常伴随着一个 src/theme目录,其中包含所有组件。

总结一下:

  • 主题与插件共享相同的生命周期方法
  • 在所有现有插件之后才运行主题
  • 存在通过扩展 webpack 配置来添加组件别名的主题

开发自定义的 Docusaurus 主题

Docusaurus 主题通常包括一个 index.js 文件,你可以在此文件中调用生命周期方法,以及一个存放组件的 theme/ 目录。一个典型的 Docusaurus 主题的 theme 目录如下所示:

website
├── package.json
└── src
    ├── index.js
    └── theme
├── MyThemeComponent └── AnotherThemeComponent.js

有两个生命周期方法对于实现主题至关重要:

These lifecycle method are not essential but recommended: