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 { useData } from "vitepress";
const { page } = useData();
import { ref, watchEffect } from "vue";
import pangu from "pangu";
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.spacing(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>