Appearance
主题定制指南
本指南将帮助你了解如何定制 vitepress-theme-components 主题,包括样式定制、布局修改和功能扩展。
主题架构
布局系统
主题采用分层布局架构:
DynamicLayout (动态布局)
├── BaseLayout (基础布局)
│ └── VitePress 默认布局
└── EmptyLayout (空布局)
└── 自定义页面布局组件层次
typescript
// src/index.ts
const theme: Theme = {
Layout: DynamicLayout,
enhanceApp(ctx) {
// 全局组件注册
ctx.app.component('LiveEditor', LiveEditor);
ctx.app.component('Mermaid', Mermaid);
}
};样式定制
1. CSS 变量覆盖
主题继承了 VitePress 的 CSS 变量系统,你可以通过覆盖这些变量来定制样式:
css
/* .vitepress/theme/custom.css */
:root {
/* 主色调 */
--vp-c-brand-1: #646cff;
--vp-c-brand-2: #747bff;
--vp-c-brand-3: #535bf2;
/* 背景色 */
--vp-c-bg: #ffffff;
--vp-c-bg-alt: #f6f6f7;
--vp-c-bg-soft: #f6f6f7;
/* 边框色 */
--vp-c-border: #c2c2c4;
--vp-c-divider: #e2e2e3;
/* 文字色 */
--vp-c-text-1: #213547;
--vp-c-text-2: #476582;
--vp-c-text-3: #7c7c7c;
}
/* 暗色主题 */
.dark {
--vp-c-bg: #1b1b1f;
--vp-c-bg-alt: #161618;
--vp-c-bg-soft: #202127;
--vp-c-border: #3c3f44;
--vp-c-divider: #2e2e32;
--vp-c-text-1: #ffffff;
--vp-c-text-2: #a8a8a8;
--vp-c-text-3: #8e8e8e;
}2. 组件样式定制
LiveEditor 样式定制
css
/* 自定义 LiveEditor 样式 */
.react-live-comp-wrapper {
border-radius: 8px;
overflow: hidden;
}
.react-live-comp-demo-wrapper {
padding: 24px;
background: var(--vp-c-bg-soft);
border-bottom: 1px solid var(--vp-c-border);
}
/* 代码编辑器样式 */
.monaco-editor {
border-radius: 0 0 8px 8px;
}
/* 预览背景切换 */
.svg-bg {
background: repeating-linear-gradient(
135deg,
transparent 0px,
transparent 32px,
var(--vp-c-bg-soft) 32px,
var(--vp-c-bg-soft) 64px
);
}3. 引入自定义样式
typescript
// .vitepress/theme/index.ts
import theme from 'vitepress-theme-components';
import './custom.css';
export default theme;布局定制
1. 自定义布局组件
创建自定义布局组件:
vue
<!-- .vitepress/theme/CustomLayout.vue -->
<template>
<div class="custom-layout">
<header class="custom-header">
<!-- 自定义头部 -->
</header>
<main class="custom-main">
<Content />
</main>
<footer class="custom-footer">
<!-- 自定义底部 -->
</footer>
</div>
</template>
<script setup lang="ts">
import { Content } from 'vitepress';
</script>
<style scoped>
.custom-layout {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.custom-main {
flex: 1;
padding: 20px;
}
</style>2. 注册自定义布局
typescript
// .vitepress/theme/index.ts
import theme from 'vitepress-theme-components';
import CustomLayout from './CustomLayout.vue';
export default {
extends: theme,
Layout: CustomLayout,
enhanceApp(ctx) {
// 继承原有的组件注册
theme.enhanceApp?.(ctx);
// 注册自定义组件
ctx.app.component('CustomComponent', CustomComponent);
}
};3. 条件布局
基于页面路径使用不同布局:
vue
<!-- .vitepress/theme/ConditionalLayout.vue -->
<template>
<CustomLayout v-if="isCustomPage" />
<DynamicLayout v-else />
</template>
<script setup lang="ts">
import { useRoute } from 'vitepress';
import { computed } from 'vue';
import DynamicLayout from 'vitepress-theme-components/lib/components/dynamic-layout.vue';
import CustomLayout from './CustomLayout.vue';
const route = useRoute();
const isCustomPage = computed(() => {
return route.path.startsWith('/custom/');
});
</script>组件扩展
1. 扩展现有组件
vue
<!-- .vitepress/theme/ExtendedLiveEditor.vue -->
<template>
<div class="extended-live-editor">
<div class="editor-toolbar">
<button @click="resetCode">重置代码</button>
<button @click="copyCode">复制代码</button>
</div>
<LiveEditor v-bind="$attrs" :sourceCode="currentCode" />
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import LiveEditor from 'vitepress-theme-components/lib/components/live-editor.vue';
const props = defineProps<{
sourceCode?: string;
}>();
const currentCode = ref(props.sourceCode);
const resetCode = () => {
currentCode.value = props.sourceCode;
};
const copyCode = async () => {
await navigator.clipboard.writeText(currentCode.value || '');
};
watch(() => props.sourceCode, (newCode) => {
currentCode.value = newCode;
});
</script>2. 创建新组件
vue
<!-- .vitepress/theme/CodeComparison.vue -->
<template>
<div class="code-comparison">
<div class="comparison-header">
<h3>代码对比</h3>
</div>
<div class="comparison-content">
<div class="before-section">
<h4>修改前</h4>
<LiveEditor :sourceCode="beforeCode" hideCode />
</div>
<div class="after-section">
<h4>修改后</h4>
<LiveEditor :sourceCode="afterCode" hideCode />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import LiveEditor from 'vitepress-theme-components/lib/components/live-editor.vue';
defineProps<{
beforeCode: string;
afterCode: string;
}>();
</script>
<style scoped>
.code-comparison {
border: 1px solid var(--vp-c-border);
border-radius: 8px;
overflow: hidden;
margin: 20px 0;
}
.comparison-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1px;
background: var(--vp-c-border);
}
.before-section,
.after-section {
background: var(--vp-c-bg);
padding: 16px;
}
</style>配置扩展
1. 扩展主题配置
typescript
// types/theme.ts
import { AdvThemeConfig } from 'vitepress-theme-components';
export interface ExtendedThemeConfig extends AdvThemeConfig {
// 自定义配置
customFeatures?: {
enableCodeComparison?: boolean;
enableAdvancedSearch?: boolean;
analytics?: {
provider: 'google' | 'baidu';
id: string;
};
};
// 社交链接
socialLinks?: {
github?: string;
twitter?: string;
discord?: string;
};
}2. 使用扩展配置
typescript
// .vitepress/config.ts
import { defineConfigWithTheme } from 'vitepress';
import { baseConfig } from 'vitepress-theme-components/config';
import { ExtendedThemeConfig } from './types/theme';
export default defineConfigWithTheme<ExtendedThemeConfig>({
extends: baseConfig,
themeConfig: {
// 原有配置
changelog: {
path: '/CHANGELOG.md'
},
coverage: {
path: '/coverage-summary.json'
},
// 扩展配置
customFeatures: {
enableCodeComparison: true,
enableAdvancedSearch: true,
analytics: {
provider: 'google',
id: 'GA_MEASUREMENT_ID'
}
},
socialLinks: {
github: 'https://github.com/your-username/your-repo',
twitter: 'https://twitter.com/your-username'
}
}
});插件集成
1. 集成第三方插件
typescript
// .vitepress/config.ts
import { defineConfig } from 'vitepress';
import { baseConfig } from 'vitepress-theme-components/config';
import { searchPlugin } from 'vitepress-plugin-search';
import { pwaPlugin } from 'vitepress-plugin-pwa';
export default defineConfig({
extends: baseConfig,
vite: {
plugins: [
searchPlugin({
// 搜索配置
}),
pwaPlugin({
// PWA 配置
})
]
}
});2. 自定义 Markdown 插件
typescript
// plugins/custom-markdown.ts
import { MarkdownRenderer } from 'vitepress';
export function customMarkdownPlugin(md: MarkdownRenderer) {
// 自定义容器
md.use(require('markdown-it-container'), 'custom-tip', {
render: function (tokens, idx) {
const token = tokens[idx];
if (token.nesting === 1) {
return '<div class="custom-tip">\n';
} else {
return '</div>\n';
}
}
});
// 自定义渲染规则
md.renderer.rules.strong_open = () => '<strong class="custom-strong">';
md.renderer.rules.strong_close = () => '</strong>';
}国际化支持
1. 多语言配置
typescript
// .vitepress/config.ts
export default defineConfig({
locales: {
root: {
label: '简体中文',
lang: 'zh-CN',
themeConfig: {
nav: [
{ text: '指南', link: '/guide/' },
{ text: '组件', link: '/components/' }
]
}
},
en: {
label: 'English',
lang: 'en-US',
themeConfig: {
nav: [
{ text: 'Guide', link: '/en/guide/' },
{ text: 'Components', link: '/en/components/' }
]
}
}
}
});2. 组件国际化
vue
<!-- components/I18nComponent.vue -->
<template>
<div>
<h2>{{ t('component.title') }}</h2>
<p>{{ t('component.description') }}</p>
</div>
</template>
<script setup lang="ts">
import { useI18n } from '../composables/useI18n';
const { t } = useI18n();
</script>性能优化
1. 代码分割
typescript
// .vitepress/theme/index.ts
import { defineAsyncComponent } from 'vue';
export default {
extends: theme,
enhanceApp(ctx) {
// 异步加载大型组件
ctx.app.component('HeavyComponent', defineAsyncComponent(
() => import('./components/HeavyComponent.vue')
));
}
};2. 资源优化
typescript
// .vitepress/config.ts
export default defineConfig({
vite: {
build: {
rollupOptions: {
output: {
manualChunks: {
'monaco-editor': ['monaco-editor'],
'react-live': ['react-live'],
'mermaid': ['mermaid']
}
}
}
}
}
});部署定制
1. 构建优化
typescript
// .vitepress/config.ts
export default defineConfig({
build: {
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
},
// 静态资源处理
assetsDir: 'static',
// 基础路径
base: '/your-project/'
});2. CDN 配置
typescript
// .vitepress/config.ts
export default defineConfig({
vite: {
build: {
rollupOptions: {
external: ['react', 'react-dom', 'vue'],
output: {
globals: {
'react': 'React',
'react-dom': 'ReactDOM',
'vue': 'Vue'
}
}
}
}
},
head: [
['script', { src: 'https://unpkg.com/react@18/umd/react.production.min.js' }],
['script', { src: 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js' }],
['script', { src: 'https://unpkg.com/vue@3/dist/vue.global.prod.js' }]
]
});最佳实践
1. 组件设计原则
- 单一职责:每个组件只负责一个功能
- 可复用性:设计通用的、可配置的组件
- 可访问性:遵循 WCAG 无障碍指南
- 性能优先:避免不必要的重渲染
2. 样式管理
- CSS 变量:使用 CSS 变量实现主题切换
- 作用域样式:使用 scoped 样式避免污染
- 响应式设计:确保在各种设备上的良好体验
3. 文档维护
- 版本控制:记录每次定制的变更
- 文档同步:保持定制文档与代码同步
- 示例完整:提供完整的使用示例
通过这个定制指南,你可以根据项目需求灵活地定制主题的各个方面,创建独特的文档体验。