前言
我需要根據動態設定導航。
比如根據不同的路由設定不同的頂部導航。
但是vitepress並沒有相關配置,但是我們可以透過攔截主題修改全域性狀態來完成這個功能!
核心知識
建立檔案,xxx/docs/.vitepress/theme/index.js
注意檔名和路徑不能寫錯,意思是覆蓋預設主題配置!
import DefaultTheme from "vitepress/theme";
import { watch } from 'vue'
export default {
extends: DefaultTheme,
enhanceApp({ app, router, siteData }) {
watch(
() => router.route.path,
(val) => {
// 動態修改站點資料(畢竟使用useData不生效),比如這裡動態設定navbar
siteData.value = {
...siteData.value,
themeConfig: {
...siteData.value.themeConfig,
nav: [
{ text: "Html", link: "/vue/intro" },
{ text: "Css", link: "/vuex/intro" },
]
}
}
}
);
},
};
完整試例
建立導航配置
nav-group.ts
import holyTrinityImg from "./assets/img/docss/holy-trinity.webp";
import feFwLibImg from "./assets/img/docss/fe-fw-lib.png";
import feErgImg from "./assets/img/docss/fe-erg.png";
const navGroup= {
holyTrinity: {
title: "前端三劍客",
content: "html、css、js的愛恨情仇",
icon: holyTrinityImg,
nav: [
{ text: "Html", link: "/html/intro" },
{ text: "Css", link: "/css/intro" },
],
},
feFwAndLib: {
title: "前端框架與庫",
content: "讓你事半功倍",
icon: feFwLibImg,
nav: [
{ text: "Vue", link: "/vue/intro" },
{ text: "Vuex", link: "/vuex/intro" },
],
},
};
export default navGroup;
動態設定導航
我們根據不同路由,匹配並展示不同的導航
xxx/docs/.vitepress/theme/index.ts
import DefaultTheme from "vitepress/theme";
import Home from "./home.vue";
import { watch } from 'vue'
import navGroup from "./nav-group";
const getNavs = (currentRoute, siteBaseUrl) => {
siteBaseUrl = siteBaseUrl.slice(0, -1);
currentRoute = currentRoute.replace(/\.[^/.]+$/, "");
for (const key in navGroup) {
const match = navGroup[key].nav?.find(it => (siteBaseUrl + it.link) === currentRoute);
if (match) return navGroup[key].nav; // 返回找到的根鍵,例如 'holyTrinity'
}
return null;
}
export default {
extends: DefaultTheme,
enhanceApp({ app, router, siteData }) {
watch(
() => router.route.path,
(val) => {
const nav = getNavs(val, siteData.value.base);
console.log(nav);
// 動態修改站點資料(畢竟使用useData不生效),比如這裡動態設定navbar
if (nav) {
siteData.value = {
...siteData.value,
themeConfig: {
...siteData.value.themeConfig,
nav
}
}
}
}
);
app.component("customHome", Home);
},
};
自定義home頁
xxx/docs/.vitepress/theme/home.vue
<template>
<div class="home">
<div class="other"></div>
<div class="docss">
<template v-for="key in Object.keys(navGroup)" :key="key">
<div class="docs">
<img :src="navGroup[key].icon" />
<div class="content">{{ navGroup[key].content }}</div>
<div class="title" @click="goByNavGroup(navGroup[key])">
{{ navGroup[key].title }}
</div>
</div>
</template>
</div>
</div>
</template>
<script setup name="customHome" lang="ts">
// @ts-nocheck
import navGroup from "./nav-group";
import { useRouter, useData } from "vitepress";
const data = useData()
const router = useRouter();
const goByNavGroup = (item) => {
const [{ link }] = item.nav;
let base = data.site.value.base
base = base.slice(0, -1);
router.go(base + link);
};
</script>
<style scoped lang="scss">
.home {
width: 100%;
max-width: 1024px;
background-color: rgba($color: #000000, $alpha: 0.01);
height: 100vh;
margin: auto;
.other {
height: 100px;
}
.docss {
margin: auto;
display: flex;
flex-wrap: wrap;
.docs {
padding: 0 16px;
// height: 180px;
margin-bottom: 20px;
cursor: pointer;
img {
width: 100%;
border-radius: 4px;
background-color: rgba($color: #000000, $alpha: 0.1);
}
.title {
text-align: center;
font-weight: 700;
}
.content {
text-align: center;
font-size: 13px;
}
}
// 媒體查詢:當螢幕寬度小於600px時
@media screen and (max-width: 600px) {
.docs {
width: 50%;
img {
height: 90px;
}
}
}
// 媒體查詢:當螢幕寬度在400px到600px之間時
@media screen and (min-width: 600px) and (max-width: 800px) {
.docs {
width: 33%;
img {
height: 110px;
}
}
}
// 媒體查詢:當螢幕寬度大於800px時
@media screen and (min-width: 800px) {
.docs {
width: 25%;
img {
height: 130px;
}
}
}
}
}
</style>