跳至內容

延伸預設佈景主題

VitePress 的預設佈景主題針對文件最佳化,而且可以自訂。請參閱 預設佈景主題設定檔總覽 以取得選項的完整清單。

不過,有許多情況光是設定檔還不夠。例如

  1. 您需要調整 CSS 樣式;
  2. 您需要修改 Vue 應用程式實例,例如註冊全域元件;
  3. 您需要透過版面配置插入自訂內容到佈景主題。

這些進階自訂需要使用「延伸」預設佈景主題的自訂佈景主題。

提示

在繼續之前,請務必先閱讀 使用自訂佈景主題 以了解自訂佈景主題如何運作。

自訂 CSS

預設佈景主題 CSS 可以透過覆寫根層級 CSS 變數來自訂

js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import './custom.css'

export default DefaultTheme
css
/* .vitepress/theme/custom.css */
:root {
  --vp-c-brand-1: #646cff;
  --vp-c-brand-2: #747bff;
}

請參閱 預設佈景主題 CSS 變數,這些變數可以被覆寫。

使用不同的字型

VitePress 使用 Inter 作為預設字型,而且會將字型包含在建置輸出中。字型也會在製作環境中自動預載入。不過,如果您想要使用不同的主字型,這可能就不合適。

若要避免將 Inter 包含在建置輸出中,請從 vitepress/theme-without-fonts 匯入主題

js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme-without-fonts'
import './my-fonts.css'

export default DefaultTheme
css
/* .vitepress/theme/custom.css */
:root {
  --vp-font-family-base: /* normal text font */
  --vp-font-family-mono: /* code font */
}

警告

如果您正在使用選用元件,例如 團隊頁面 元件,請務必也從 vitepress/theme-without-fonts 匯入它們!

如果您的字型是透過 @font-face 參照的本機檔案,它將會被處理為資產,並包含在 .vitepress/dist/assets 中,且檔名已雜湊。若要預載這個檔案,請使用 transformHead 建置掛勾

js
// .vitepress/config.js
export default {
  transformHead({ assets }) {
    // adjust the regex accordingly to match your font
    const myFontFile = assets.find(file => /font-name\.\w+\.woff2/)
    if (myFontFile) {
      return [
        [
          'link',
          {
            rel: 'preload',
            href: myFontFile,
            as: 'font',
            type: 'font/woff2',
            crossorigin: ''
          }
        ]
      ]
    }
  }
}

註冊全域元件

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

/** @type {import('vitepress').Theme} */
export default {
  extends: DefaultTheme,
  enhanceApp({ app }) {
    // register your custom global components
    app.component('MyGlobalComponent' /* ... */)
  }
}

如果您使用 TypeScript

ts
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'

export default {
  extends: DefaultTheme,
  enhanceApp({ app }) {
    // register your custom global components
    app.component('MyGlobalComponent' /* ... */)
  }
} satisfies Theme

由於我們使用 Vite,您也可以利用 Vite 的 glob 匯入功能 自動註冊元件目錄。

版面插槽

預設主題的 <Layout/> 元件有幾個插槽,可用於在頁面的特定位置注入內容。以下是將元件注入到輪廓之前的一個範例

js
// .vitepress/theme/index.js
import DefaultTheme from 'vitepress/theme'
import MyLayout from './MyLayout.vue'

export default {
  extends: DefaultTheme,
  // override the Layout with a wrapper component that
  // injects the slots
  Layout: MyLayout
}
vue
<!--.vitepress/theme/MyLayout.vue-->
<script setup>
import DefaultTheme from 'vitepress/theme'

const { Layout } = DefaultTheme
</script>

<template>
  <Layout>
    <template #aside-outline-before>
      My custom sidebar top content
    </template>
  </Layout>
</template>

您也可以使用渲染函數。

js
// .vitepress/theme/index.js
import { h } from 'vue'
import DefaultTheme from 'vitepress/theme'
import MyComponent from './MyComponent.vue'

export default {
  extends: DefaultTheme,
  Layout() {
    return h(DefaultTheme.Layout, null, {
      'aside-outline-before': () => h(MyComponent)
    })
  }
}

預設主題版面中可用的插槽完整清單

  • 當透過 frontmatter 啟用 layout: 'doc'(預設)時
    • doc-top
    • doc-bottom
    • doc-footer-before
    • doc-before
    • doc-after
    • sidebar-nav-before
    • sidebar-nav-after
    • aside-top
    • aside-bottom
    • aside-outline-before
    • aside-outline-after
    • aside-ads-before
    • aside-ads-after
  • 當透過 frontmatter 啟用 layout: 'home'
    • home-hero-before
    • home-hero-info-before
    • home-hero-info
    • home-hero-info-after
    • home-hero-actions-after
    • home-hero-image
    • home-hero-after
    • home-features-before
    • home-features-after
  • 當透過 frontmatter 啟用 layout: 'page'
    • page-top
    • page-bottom
  • 在找不到(404)頁面時
    • not-found
  • 始終
    • 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

使用檢視轉場 API

在變更外觀時

您可以延伸預設主題,以便在切換色彩模式時提供自訂轉場。一個範例

vue
<!-- .vitepress/theme/Layout.vue -->

<script setup lang="ts">
import { useData } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import { nextTick, provide } from 'vue'

const { isDark } = useData()

const enableTransitions = () =>
  'startViewTransition' in document &&
  window.matchMedia('(prefers-reduced-motion: no-preference)').matches

provide('toggle-appearance', async ({ clientX: x, clientY: y }: MouseEvent) => {
  if (!enableTransitions()) {
    isDark.value = !isDark.value
    return
  }

  const clipPath = [
    `circle(0px at ${x}px ${y}px)`,
    `circle(${Math.hypot(
      Math.max(x, innerWidth - x),
      Math.max(y, innerHeight - y)
    )}px at ${x}px ${y}px)`
  ]

  await document.startViewTransition(async () => {
    isDark.value = !isDark.value
    await nextTick()
  }).ready

  document.documentElement.animate(
    { clipPath: isDark.value ? clipPath.reverse() : clipPath },
    {
      duration: 300,
      easing: 'ease-in',
      pseudoElement: `::view-transition-${isDark.value ? 'old' : 'new'}(root)`
    }
  )
})
</script>

<template>
  <DefaultTheme.Layout />
</template>

<style>
::view-transition-old(root),
::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

::view-transition-old(root),
.dark::view-transition-new(root) {
  z-index: 1;
}

::view-transition-new(root),
.dark::view-transition-old(root) {
  z-index: 9999;
}

.VPSwitchAppearance {
  width: 22px !important;
}

.VPSwitchAppearance .check {
  transform: none !important;
}
</style>

結果(警告!:閃爍色彩、突然移動、強光)

示範

Appearance Toggle Transition Demo

請參閱 Chrome 文件,以取得檢視轉場的更多詳細資訊。

在變更路由時

即將推出。

覆寫內部組件

你可以使用 Vite 的 別名 來替換預設主題組件為你的自訂組件

ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vitepress'

export default defineConfig({
  vite: {
    resolve: {
      alias: [
        {
          find: /^.*\/VPNavBar\.vue$/,
          replacement: fileURLToPath(
            new URL('./components/CustomNavBar.vue', import.meta.url)
          )
        }
      ]
    }
  }
})

若要得知組件的確切名稱,請參閱 我們的原始碼。由於這些組件是內部的,因此它們的名稱在小版本更新之間更新的機率很低。

在 MIT 授權條款下發布。