Swizzle
在本节中,我们将介绍如何在 Docusaurus 中完成自定义布局。
听起来有点耳熟……?
This section is similar to Styling and Layout, but this time, we will customize React components themselves, rather than what they look like. 我们会讨论 Docusaurus 的一个核心概念:swizzle。Swizzle 允许你进行更深入的网站定制。
实际操作中,swizzle 允许你把一个主题组件替换为你自己的实现。它有两种模式:
为什么叫 swizzle?
这个名字来自 Objective-C 和 Swift-UI:通过 method swizzle(有时候翻译成「方法交换」),你可以替换一个现有选择器(或方法)的 实现。
对于 Docusaurus 来说,swizzle 组件意味着提供一个替代组件,它会优先于主题提供的组件。
你可以把它当作是 React 组件的猴子补丁 (monkey patch),使你能够覆盖默认的实现。 Gatsby 有一个类似的概念,叫做 theme shadowing。
要更深入地理解这一点,你必须明白主题组件是如何被解析的。
Swizzle 的过程
概览
Docusaurus provides a convenient interactive CLI to swizzle components. 你一般只需要记住以下指令:
- npm
- Yarn
- pnpm
npm run swizzle
yarn swizzle
pnpm run swizzle
它将在你的 src/theme
目录中生成一个新组件,组件看起来和这个示例类似:
- 弹出
- 包装
import React from 'react';
export default function SomeComponent(props) {
// 你可以完全自定义这个实现,包括改变 JSX, CSS 和 React 钩子
return (
<div className="some-class">
<h1>某个组件</h1>
<p>一些组件实现细节</p>
</div>
);
}
import React from 'react';
import SomeComponent from '@theme-original/SomeComponent';
export default function SomeComponentWrapper(props) {
// 你可以增强原组件,包括添加额外的属性或其他 JSX 元素
return (
<>
<SomeComponent {...props} />
</>
);
}
要总览所有可用的主题和组件,请运行:
- npm
- Yarn
- pnpm
npm run swizzle -- --list
yarn swizzle --list
pnpm run swizzle -- --list
你可以用 --help
查看所有可用的 CLI 选项,或参考 swizzle CLI 文档。
在 swizzle 组件后,重新启动你的开发服务器,让 Docusaurus 能意识到新组件的存在。
确保你清楚哪些组件是能被安全 swizzle 的。 某些组件是主题的内部实现细节。
docusaurus swizzle
只是一种帮助你 swizzle 组件的自动化方式。 你也可以手动创建 src/theme/SomeComponent.js
文件,Docusaurus 也会解析它。 这个命令背后没有什么内部的魔法!
弹出组件
弹出主题组件的过程会创建一个原始主题组件的复制版。你可以完全自定义并覆盖原组件。
要弹出主题组件,可以使用交互式 swizzle CLI,或使用 --eject
选项:
- npm
- Yarn
- pnpm
npm run swizzle [主题名] [组 件名] -- --eject
yarn swizzle [主题名] [组件名] --eject
pnpm run swizzle [主题名] [组件名] -- --eject
举个例子:
- npm
- Yarn
- pnpm
npm run swizzle @docusaurus/theme-classic Footer -- --eject
yarn swizzle @docusaurus/theme-classic Footer --eject
pnpm run swizzle @docusaurus/theme-classic Footer -- --eject
这会把现有的 <Footer />
组件的实现复制到你的站点的 src/theme
目录。 Docusaurus 现在会使用这个 <Footer>
组件副本,而不是原组件。 你现在可以自由地重新实现 <Footer>
组件了。
import React from 'react';
export default function Footer(props) {
return (
<footer>
<h1>这是我自定义的网站页脚</h1>
<p>它和原本的那个完全不一样</p>
</footer>
);
}
在更新 Docusaurus 后,如果需要保持弹出的组件最新,可以再次运行弹出指令,并用 git diff
比较变化。 也建议你在文件顶部写一个简短的注释,说明你做了哪些修改。这样你可以在重弹出后更容易地重新做更改。
包装组件
包装主题组件的过程会创建一个原始主题组件的包装层。你可以增强原组件。
要包装主题组件,可以使用交互式 swizzle CLI,或使用 --wrap
选项:
- npm
- Yarn
- pnpm
npm run swizzle [主题名] [组件名] -- --wrap
yarn swizzle [主题名] [组件名] --wrap
pnpm run swizzle [主题名] [组件名] -- --wrap
举个例子:
- npm
- Yarn
- pnpm
npm run swizzle @docusaurus/theme-classic Footer -- --wrap
yarn swizzle @docusaurus/theme-classic Footer --wrap
pnpm run swizzle @docusaurus/theme-classic Footer -- --wrap
这会在你的站点的 src/theme
目录中创建一个包装组件。 Docusaurus 现在会使用这个 <FooterWrapper>
组件,而不是原始组件。 你现在可以在原始组件周围添加自定义内容。
import React from 'react';
import Footer from '@theme-original/Footer';
export default function FooterWrapper(props) {
return (
<>
<section>
<h2>额外部分</h2>
<p>这是在原先的页脚上面的一个额 外部分</p>
</section>
<Footer {...props} />
</>
);
}
这个 @theme-original
是什么?
Docusaurus 通过主题别名来解析最终会被使用的主题组件。 新创建的包装组件会占据 @theme/SomeComponent
这个别名。 @theme-original/SomeComponent
允许导入包装组件所覆盖的原始组件,而不会因为包装组件导入自己,产生无限导入循环。
如果你想要在现有组件周围添加额外组件,包装主题的方法很不错,不需要弹出