Skip to content

VitePress 文章顶部面包屑

基本逻辑

扩展默认主题,并通过 VitePress 内置主题提供的 doc-before 布局插槽,把面包屑 Vue 组件塞进去。面包屑组件通过 useData() API 获取当前页面路径并用 v-for 渲染。

代码实现

ts
import DefaultTheme from "vitepress/theme";
import Layout from "./layout.vue";

export default <Theme>{
  extends: DefaultTheme,
  Layout,
  // ...
};
vue
<template>
  <Layout>
    <template #doc-before>
      <Breadcrumb />
    </template>
    <!-- ... -->
  </Layout>
</template>

<script setup lang="ts">
import Breadcrumb from "./components/breadcrumb.vue";
// ...
</script>
vue
<template>
  <div id="breadcrumb">
    <span v-for="item in items" class="bc-items" :id="item.first ? 'bc-project' : undefined">{{
      item.name
    }}</span>
  </div>
</template>

<script setup lang="ts">
import pangu from 'pangu'
import { useData } from 'vitepress'
import { ref, watchEffect } from 'vue'

const { page } = useData()

type Breadcrumb = {
  name: string
  first: boolean
}

const items = ref<Breadcrumb[]>([])
watchEffect(() => {
  const pathSegs = page.value.filePath.split('/')
  const shownSegs = pathSegs.at(-1) === 'index.md' ? pathSegs.slice(0, -2) : pathSegs.slice(0, -1)
  // 面包屑只显示到当前页面的上一级,不包含页面标题
  // 如果是首页,则一并去除当前目录名

  items.value = shownSegs.map((item, index) => ({
    name: pangu.spacingText(item.replaceAll('-', ' ')),
    first: !index,
  }))
})
</script>

<style>
#breadcrumb {
  margin-bottom: 15px;
  font-size: 15px;
  color: var(--vp-c-text-2);
}
.bc-items::after {
  content: '/';
  margin: 0 8px;
  vertical-align: top;
  font-weight: bold;
  font-size: 10px;
  color: var(--vp-c-text-3);
}
</style>

相关文档