Skip to content

主题 API

VitePress 主题是一个包含组件和样式的集合,本节介绍主题开发相关的 API。

主题入口文件

主题入口文件位于 .vitepress/theme/index.ts

接口定义

ts
interface Theme {
  // 扩展默认主题
  extends?: Theme
  
  // 布局组件
  Layout?: Component
  
  // 404 组件
  NotFound?: Component
  
  // 应用增强函数
  enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>
  
  // setup 函数
  setup?: () => void
}

扩展默认主题

基础扩展

ts
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'

export default {
  extends: DefaultTheme
}

添加自定义样式

ts
import DefaultTheme from 'vitepress/theme'
import './custom.css'

export default {
  extends: DefaultTheme
}

注册全局组件

ts
import DefaultTheme from 'vitepress/theme'
import MyComponent from './components/MyComponent.vue'

export default {
  extends: DefaultTheme,
  enhanceApp({ app }) {
    app.component('MyComponent', MyComponent)
  }
}

安装 Vue 插件

ts
import DefaultTheme from 'vitepress/theme'
import { createPinia } from 'pinia'

export default {
  extends: DefaultTheme,
  enhanceApp({ app }) {
    app.use(createPinia())
  }
}

自定义主题

完全自定义主题需要提供 Layout 组件。

基础结构

ts
// .vitepress/theme/index.ts
import Layout from './Layout.vue'

export default {
  Layout,
  NotFound: () => import('./NotFound.vue'),
  enhanceApp({ app }) {
    // 注册全局组件和插件
  }
}

Layout 组件

vue
<!-- .vitepress/theme/Layout.vue -->
<script setup lang="ts">
import { useData } from 'vitepress'

const { page, frontmatter } = useData()
</script>

<template>
  <div class="theme">
    <header>导航栏</header>
    <main>
      <Content />
    </main>
    <footer>页脚</footer>
  </div>
</template>

布局插槽

默认主题提供了一系列插槽用于扩展布局。

Layout 插槽

vue
<!-- .vitepress/theme/index.ts -->
import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'

export default {
  extends: DefaultTheme,
  Layout: MyLayout
}
vue
<!-- .vitepress/theme/MyLayout.vue -->
<script setup>
import DefaultTheme from 'vitepress/theme'
const { Layout } = DefaultTheme
</script>

<template>
  <Layout>
    <!-- 导航栏前 -->
    <template #nav-bar-title-before>
      <span class="logo-icon">🚀</span>
    </template>
    
    <!-- 导航栏后 -->
    <template #nav-bar-content-after>
      <div class="custom-nav">自定义内容</div>
    </template>
    
    <!-- 侧边栏前 -->
    <template #sidebar-nav-before>
      <div class="sidebar-header">导航</div>
    </template>
    
    <!-- 文档前 -->
    <template #doc-before>
      <div class="doc-header">文档头</div>
    </template>
    
    <!-- 文档后 -->
    <template #doc-after>
      <div class="doc-footer">文档脚</div>
    </template>
    
    <!-- 页脚前 -->
    <template #doc-footer-before>
      <div class="custom-footer">自定义页脚</div>
    </template>
  </Layout>
</template>

可用插槽列表

插槽名称说明
layout-top布局顶部
layout-bottom布局底部
nav-bar-title-before导航标题前
nav-bar-title-after导航标题后
nav-bar-content-before导航内容前
nav-bar-content-after导航内容后
nav-screen-content-before移动端导航前
nav-screen-content-after移动端导航后
sidebar-nav-before侧边栏导航前
sidebar-nav-after侧边栏导航后
doc-before文档内容前
doc-after文档内容后
doc-footer-before页脚前
aside-top大纲顶部
aside-bottom大纲底部
aside-outline-before大纲前
aside-outline-after大纲后
aside-ads-before广告前
aside-ads-after广告后

enhanceApp

应用增强函数,用于注册全局组件、插件等。

参数

ts
interface EnhanceAppContext {
  app: App      // Vue 应用实例
  router: Router // VitePress 路由
  siteData: Ref<SiteData> // 站点数据
}

注册全局组件

ts
export default {
  enhanceApp({ app }) {
    // 单个注册
    app.component('MyButton', () => import('./components/MyButton.vue'))
    
    // 批量注册
    const components = import.meta.glob('./components/*.vue')
    for (const [path, component] of Object.entries(components)) {
      const name = path.match(/\/([^/]+)\.vue$/)[1]
      app.component(name, component)
    }
  }
}

添加全局指令

ts
export default {
  enhanceApp({ app }) {
    app.directive('focus', {
      mounted(el) {
        el.focus()
      }
    })
  }
}

提供全局数据

ts
export default {
  enhanceApp({ app }) {
    app.provide('globalConfig', {
      api: 'https://api.example.com'
    })
  }
}

useData

获取页面数据的组合式函数。

ts
import { useData } from 'vitepress'

const {
  page,        // 当前页面数据
  frontmatter, // frontmatter 数据
  theme,       // 主题配置
  site,        // 站点数据
  lang,        // 当前语言
  title,       // 页面标题
  description  // 页面描述
} = useData()

useRoute

获取当前路由信息。

ts
import { useRoute } from 'vitepress'

const route = useRoute()

console.log(route.path)        // 当前路径
console.log(route.data)        // 页面数据
console.log(route.component)   // 页面组件

useRouter

访问路由器实例。

ts
import { useRouter } from 'vitepress'

const router = useRouter()

// 导航
router.go('/guide/installation')

// 返回
router.go(-1)

// 监听路由变化
router.onAfterRouteChanged = (to) => {
  console.log('导航到:', to)
}

Content 组件

渲染 Markdown 内容的组件。

vue
<script setup>
import { Content } from 'vitepress'
</script>

<template>
  <Content />
</template>

Props

vue
<Content class="custom-content" />

完整主题示例

ts
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import type { Theme } from 'vitepress'
import { h } from 'vue'
import MyComponent from './components/MyComponent.vue'
import './custom.css'

export default {
  extends: DefaultTheme,
  
  Layout: () => {
    return h(DefaultTheme.Layout, null, {
      'doc-after': () => h(MyComponent)
    })
  },
  
  enhanceApp({ app, router }) {
    // 注册组件
    app.component('MyComponent', MyComponent)
    
    // 路由守卫
    router.onBeforeRouteChange = (to) => {
      console.log('即将导航到:', to)
    }
  }
} satisfies Theme

参考链接

贡献者

加载中...

想要成为贡献者?

在 CNB 上参与贡献