自定义主题 
解析主题 
你可以通过创建一个 .vitepress/theme/index.js 或 .vitepress/theme/index.ts 文件 (即“主题入口文件”) 来启用自定义主题:
.
├─ docs                # project root
│  ├─ .vitepress
│  │  ├─ theme
│  │  │  └─ index.js   # theme entry
│  │  └─ config.js     # config file
│  └─ index.md
└─ package.json.
├─ docs                # project root
│  ├─ .vitepress
│  │  ├─ theme
│  │  │  └─ index.js   # theme entry
│  │  └─ config.js     # config file
│  └─ index.md
└─ package.json2
3
4
5
6
7
8
当检测到存在主题入口文件时,VitePress 总会使用自定义主题而不是默认主题。但你可以拓展默认主题来在其基础上实现更高级的定制。
主题接口 
VitePress 自定义主题被定义为一个对象,该对象具有如下接口:
interface Theme {
	/**
	 * Root layout component for every page
	 * @required
	 */
	Layout: Component
	/**
	 * Enhance Vue app instance
	 * @optional
	 */
	enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
	/**
	 * Extend another theme, calling its `enhanceApp` before ours
	 * @optional
	 */
	extends?: Theme
}
interface EnhanceAppContext {
	app: App // Vue app instance
	router: Router // VitePress router instance
	siteData: Ref<SiteData> // Site-level metadata
}interface Theme {
	/**
	 * Root layout component for every page
	 * @required
	 */
	Layout: Component
	/**
	 * Enhance Vue app instance
	 * @optional
	 */
	enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
	/**
	 * Extend another theme, calling its `enhanceApp` before ours
	 * @optional
	 */
	extends?: Theme
}
interface EnhanceAppContext {
	app: App // Vue app instance
	router: Router // VitePress router instance
	siteData: Ref<SiteData> // Site-level metadata
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
主题入口文件需要将主题作为默认导出来导出:
// .vitepress/theme/index.js
// You can directly import Vue files in the theme entry
// VitePress is pre-configured with @vitejs/plugin-vue.
import Layout from './Layout.vue'
export default {
	Layout,
	enhanceApp({ app, router, siteData }) {
		// ...
	},
}// .vitepress/theme/index.js
// You can directly import Vue files in the theme entry
// VitePress is pre-configured with @vitejs/plugin-vue.
import Layout from './Layout.vue'
export default {
	Layout,
	enhanceApp({ app, router, siteData }) {
		// ...
	},
}2
3
4
5
6
7
8
9
10
11
12
默认导出是自定义主题的唯一方式,并且只有 Layout 属性是必须的。所以从技术上讲,一个 VitePress 主题可以只是一个单独的 Vue 组件。
在你的组件内部,它的工作方式就像是一个普通的 Vite + Vue 3 应用。请注意,主题还需要保证 SSR 兼容。
构建布局 
最基本的布局组件需要包含一个 <Content /> 组件:
<!-- .vitepress/theme/Layout.vue -->
<template>
	<h1>Custom Layout!</h1>
	<!-- this is where markdown content will be rendered -->
	<Content />
</template><!-- .vitepress/theme/Layout.vue -->
<template>
	<h1>Custom Layout!</h1>
	<!-- this is where markdown content will be rendered -->
	<Content />
</template>2
3
4
5
6
7
上面的布局只是将每个页面的 markdown 渲染为 HTML。我们添加的第一个改进是处理 404 错误:
<script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<template>
  <h1>Custom Layout!</h1>
  <div v-if="page.isNotFound">
    Custom 404 page!
  </div>
  <Content v-else />
</template><script setup>
import { useData } from 'vitepress'
const { page } = useData()
</script>
<template>
  <h1>Custom Layout!</h1>
  <div v-if="page.isNotFound">
    Custom 404 page!
  </div>
  <Content v-else />
</template>2
3
4
5
6
7
8
9
10
11
12
13
useData() 为我们提供了所有的运行时数据,以便我们根据不同条件渲染不同的布局。我们可以访问的另一个数据是当前页面的 frontmatter。通过利用这个数据,我们允许最终用户控制每个页面的布局。例如,用户可以指示一个页面是否使用特殊的主页布局:
---
layout: home
------
layout: home
---2
3
并且我们可以该信息调整我们的主题
<script setup>
import { useData } from 'vitepress'
const { page, frontmatter } = useData()
</script>
<template>
  <h1>Custom Layout!</h1>
  <div v-if="page.isNotFound">
    Custom 404 page!
  </div>
  <div v-if="frontmatter.layout === 'home'">
    Custom home page!
  </div>
  <Content v-else />
</template><script setup>
import { useData } from 'vitepress'
const { page, frontmatter } = useData()
</script>
<template>
  <h1>Custom Layout!</h1>
  <div v-if="page.isNotFound">
    Custom 404 page!
  </div>
  <div v-if="frontmatter.layout === 'home'">
    Custom home page!
  </div>
  <Content v-else />
</template>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
当然你可以将布局切分为不同的组件:
<script setup>
import { useData } from 'vitepress'
import NotFound from './NotFound.vue'
import Home from './Home.vue'
import Page from './Page.vue'
const { page, frontmatter } = useData()
</script>
<template>
  <h1>Custom Layout!</h1>
 
  <NotFound v-if="page.isNotFound" />
  <Home v-if="frontmatter.layout === 'home'" />
  <Page v-else /> <!-- <Page /> renders <Content /> -->
</template><script setup>
import { useData } from 'vitepress'
import NotFound from './NotFound.vue'
import Home from './Home.vue'
import Page from './Page.vue'
const { page, frontmatter } = useData()
</script>
<template>
  <h1>Custom Layout!</h1>
 
  <NotFound v-if="page.isNotFound" />
  <Home v-if="frontmatter.layout === 'home'" />
  <Page v-else /> <!-- <Page /> renders <Content /> -->
</template>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
请查看运行时 API 参考获取主题组件中所有可用内容。此外,你可以利用构建时数据加载 来生成数据驱动布局 - 例如,一个列出当前项目中所有博客文章的页面。
分发自定义主题 
分发自定义主题最简单的方式是通过将其作为 GitHub 模版仓库 来提供。
如果你希望将主题作为 npm 包来分发,请按照下面的步骤操作:
在包入口将主题对象作为默认导出来导出。
如果合适的话,将你的主题配置类型定义作为
ThemeConfig导出。如果你的主题需要调整 VitePress 配置,请在包子路径下 (例如
my-theme/config) 下导出该配置,以便用户拓展。记录主题配置选项 (通过配置文件和 frontmatter)。
提供清晰的说明关于如何使用你的主题 (见下文)。
使用自定义主题 
要使用外部主题,请从自定义主题入口导入导入它并重新导出:
// .vitepress/theme/index.js
import Theme from 'awesome-vitepress-theme'
export default Theme// .vitepress/theme/index.js
import Theme from 'awesome-vitepress-theme'
export default Theme2
3
4
如果主题需要被拓展:
// .vitepress/theme/index.js
import Theme from 'awesome-vitepress-theme'
export default {
	extends: Theme,
	enhanceApp(ctx) {
		// ...
	},
}// .vitepress/theme/index.js
import Theme from 'awesome-vitepress-theme'
export default {
	extends: Theme,
	enhanceApp(ctx) {
		// ...
	},
}2
3
4
5
6
7
8
9
如果主题需要特殊的 VitePress 配置,你也需要在配置中拓展:
// .vitepress/theme/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
export default {
	// extend theme base config (if needed)
	extends: baseConfig,
}// .vitepress/theme/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
export default {
	// extend theme base config (if needed)
	extends: baseConfig,
}2
3
4
5
6
7
最后,如果主题为其主题配置提供了类型:
// .vitepress/theme/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from 'awesome-vitepress-theme'
export default defineConfigWithTheme<ThemeConfig>({
	extends: baseConfig,
	themeConfig: {
		// Type is `ThemeConfig`
	},
})// .vitepress/theme/config.ts
import baseConfig from 'awesome-vitepress-theme/config'
import { defineConfigWithTheme } from 'vitepress'
import type { ThemeConfig } from 'awesome-vitepress-theme'
export default defineConfigWithTheme<ThemeConfig>({
	extends: baseConfig,
	themeConfig: {
		// Type is `ThemeConfig`
	},
})2
3
4
5
6
7
8
9
10
11