前言

我需要根据动态设置导航。

比如根据不同的路由设置不同的顶部导航。

但是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" },
]
}
}
}
);
},
};

完整试例

创建导航配置

xxx/docs/.vitepress/theme/helper/nav-group.ts

import holyTrinityImg from "../assets/img/docss/holy-trinity.webp";
import feFwLibImg from "../assets/img/docss/fe-fw-lib.png"; const navGroup = {
holyTrinity: {
title: "前端三剑客",
content: "html、css、js的爱恨情仇",
icon: holyTrinityImg,
nav: [
{ text: "Html", link: "/html" },
{ text: "Css", link: "/css" },
],
},
feFwAndLib: {
title: "前端框架与库",
content: "让你事半功倍",
icon: feFwLibImg,
nav: [
{ text: "Vue", link: "/vue" },
{ text: "Vuex", link: "/vuex" },
],
},
}; export default navGroup;

工具函数

xxx/docs/.vitepress/theme/helper/utils.ts

import _ from "lodash";
import navGroupTemp from "./nav-group"; // 接受navGrouplink,返回对应的第一个sidebar(既第一篇文档)
export const getFirstSideBarLink = (navGrouplink, allSidebar, baseUrl) => {
const sidebar = allSidebar[navGrouplink + "/"];
let firstSidebar;
const handler = (items) => {
for (const it of items) {
if (it.items) handler(it.items);
else firstSidebar = it;
break;
}
};
handler(sidebar.items);
let link;
if (firstSidebar) {
let base = baseUrl;
base = base.slice(0, -1);
link = base + navGrouplink + "/" + firstSidebar.link;
}
return link;
}; // 根据当前路由 获取 对应的顶部导航
export const getNavs = (router, baseUrl) => {
let navGroup = _.cloneDeep(navGroupTemp);
const { path } = router.route;
const index = baseUrl === "/" ? 1 : 2;
const navItemlink = "/" + path.split("/")[index];
for (const key in navGroup) {
const match = navGroup[key].nav?.find((it) => it.link === navItemlink);
if (match) return navGroup[key].nav; // 返回找到的根键,例如 'holyTrinity'
}
};

自定义主题: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 _ from 'lodash';
import {ref} from "vue";
import navGroupTemp from "./helper/nav-group";
import { useRouter, useData } from "vitepress";
import {getFirstSideBarLink} from "./helper/utils" const navGroup = ref(_.cloneDeep(navGroupTemp));
const { site, theme } = useData()
const router = useRouter();
const goByNavGroup = (item) => {
const [firstNav] = item.nav;
const link = getFirstSideBarLink(firstNav.link, theme.value.sidebar, site.value.base);
router.go(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>

自定义主题: 入口

xxx/docs/.vitepress/theme/index.ts

import _ from "lodash";
import { watch } from "vue";
import Home from "./home.vue";
import DefaultTheme from "vitepress/theme";
import { getFirstSideBarLink, getNavs } from "./helper/utils"; export default {
extends: DefaultTheme,
enhanceApp({ app, router, siteData }) {
watch(
() => router.route.path,
(val) => {
// 获取基础nav
const nav = getNavs(router, siteData.value.base);
// 动态修改站点数据(毕竟使用useData不生效),比如这里动态设置navbar
if (nav) {
// 补充完整nav的link,并设置合适的active高亮
nav.forEach((it) => {
const res = getFirstSideBarLink(
it.link,
siteData.value.themeConfig.sidebar,
""
);
it.link = res;
it.activeMatch = "/" + it.link.split("/")[1] + "/";
});
siteData.value = {
...siteData.value,
themeConfig: {
...siteData.value.themeConfig,
nav,
},
};
}
}
);
app.component("customHome", Home);
},
};

其他

注意我使用了侧边栏自动生成插件 vitepress-sidebar

xxx/docs/.vitepress/config.mts

import { defineConfig } from 'vitepress'
import { withSidebar } from 'vitepress-sidebar';
import fs from "node:fs";
import path from "node:path"; const vitePressOptions = defineConfig({
title: "丁知识库",
description: "A VitePress Site",
base: "/vitepress",
cleanUrls: true,
themeConfig: {
nav: [],
sidebar: [],
// socialLinks: [
// { icon: 'github', link: 'https://github.com/vuejs/vitepress' }
// ]
}
}) // 获取都有哪些项目
const projectRoot = path.resolve(process.cwd());
const docsPath = path.resolve(projectRoot, 'docs');
const ignoreDir = ['.vitepress', '.DS_Store'];
const docs = fs.readdirSync(docsPath, { withFileTypes: true }).filter(it => {
const isIgnore = ignoreDir.includes(it.name)
const isFile = fs.statSync(path.resolve(it.parentPath, it.name)).isFile();
return !isIgnore && !isFile;
}); const vitePressSidebarOptions = docs.map(it => ({
documentRootPath: 'docs',
scanStartPath: it.name,
basePath: `/${it.name}/`,
resolvePath: `/${it.name}/`,
useTitleFromFileHeading: true,
collapsed: true,
rootGroupCollapsed: true,
useFolderLinkFromSameNameSubFile: true, // 如果此值为true,则当存在与文件夹同名的子文件时,将在文件夹中创建一个链接,用于导航至该文件,而该文件不会显示在子项中。
// folderLinkNotIncludesFileName: true
})) export default defineConfig(withSidebar(vitePressOptions, vitePressSidebarOptions));

预览效果

vitepress动态导航的更多相关文章

  1. Jquery实现动态导航栏和轮播导航栏

    动态导航栏和轮播导航栏的实现思想: 利用jquery技术的append()方法和bind()方法实现li标签的添加和点击事件绑定,在利用$getJSON(url,data,function)请求方法实 ...

  2. 动态导航栏和JavaScript箭头函数

    动态导航栏和JavaScript箭头函数 今天我们来写一下动态的导航栏,并且学一下JavaScript的箭头函数等相关问题. 样式如下所示: html中执行代码如下所示: <!DOCTYPE h ...

  3. 纯CSS3实现动态导航栏目

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. HTML和CSS设置动态导航以及CSS中伪元素的简单说明

    HTML页面代码: <!DOCTYPE html> <html> <head> <title>Test</title> <meta c ...

  5. 巧妙使用checkbox制作纯css动态导航栏

    前提:很多时候.我们的网页都需要一个垂直的导航栏.可以分类.有分类.自然就有展开.关闭的功能.你还在使用jquery操作dom来制作吗?那你就out了! 方案:使用checkbox 的 checked ...

  6. vue-router 动态导航 router-link :to属性

    经常碰到这类需求,从后台获取数据后再前程连接,参数id动态获取 <el-row v-for="item in Travels"> <el-col :span=&q ...

  7. jsp动态导航栏

    站点页面的导航栏是从数据库中生成出来的,所以在界面上展示导航栏时,要从数据库中读取出来,但不能每次显示一个页面都从数据库中读.这样就非常浪费性能.应该考虑把导航栏放到一个缓存中.如:session.a ...

  8. vue+el-menu+vue-router实现动态导航条

    导航栏组件template <template> <div class="sidebar"> <el-menu unique-opened :defa ...

  9. 第六章节 BJROBOT 动态导航壁障

    导航前说明:一定要确保你小车在构建好地图的基础上进行! 1.把小车平放在你想要构建地图区域的地板上,打开资料里的虚拟机,打开一个终端, ssh 过去主控端启动 roslaunch znjrobot b ...

  10. vue、element-ui 依权限动态导航 v-for、v-if

    在管理后台需要按用户权限展示不同导航菜单时,我们需要从后端请求数据来进行菜单渲染. 但由于v-for与v-if不能在同一标签内使用(存在性能问题:v-for 具有比 v-if 更高的优先级,意味着 v ...

随机推荐

  1. 基于Spring Boot的HTTP请求签名验证实现解析

    概述 在分布式系统交互中,API接口的安全性至关重要.本文将深入解析基于Spring Boot实现的HTTP请求签名验证机制,该方案支持GET/POST等多种请求方式,提供时效性验证和数据完整性保障. ...

  2. GPT-SoVITS Windows 配置与推理笔记(自用)

    GPT-SoVITS Windows 配置与推理笔记(自用) 这是给自己留的备份,方便下次查.Windows 端配置和推理为主,代码为核心,直接干货. 环境准备 系统:Windows 10/11 Py ...

  3. jmeter实现幂等测试的一种方法(案例)

    最近在研究怎样对电商系统的业务进行幂等测试,利用jmeter对单独业务开展幂等测试可能简便.直接有效吧 场景描述:买家每一笔订单选中商品后,系统会生成一个"ShopCartIds" ...

  4. 关于Cesium渲染PrimitiveCollection和图层的树状管理的问题

    原文:关于Cesium渲染PrimitiveCollection和图层的树状管理的问题 - 搜栈网 (seekstack.cn)

  5. CTF实验吧:登陆一下? 不一样的SQL注入

    http://ctf5.shiyanbar.com/web/wonderkun/web/index.html 发现 过滤了很多SQL敏感字符,并且 转码绕过也并不行 发现'和=没有进行过滤 考虑万能密 ...

  6. 正点原子ALPHA开发板使用4.3寸触摸屏LCD驱动实验显示不正常

    显示问题 裸机开发时,驱动教程的PDF里给了4.3寸LCD屏幕的设置参数.如下图所示: 但是按照这个设置,编写设备树dts文件,下载到开发板里,却出现了显示异常,具体来说就是帧率不对,图和字都是歪斜的 ...

  7. 『Plotly实战指南』--Plotly与Pandas的深度融合

    在数据分析的世界中,数据处理与可视化是密不可分的两个环节. Pandas作为Python数据处理的核心工具,以其强大的数据清洗.转换和分析能力,成为数据科学家和分析师的必备利器: 而Plotly则是交 ...

  8. Mysql 常用时间函数(上)

    也是做数据分析嘛, SQL 必然是每天都要用的, 然后在分析中, 时间是数据分析中极为重要的部分, 可以说是承上启下或者是贯穿整个分析. 比如, 日, 周, 月, 季度, 年度 与之相对应的 环比, ...

  9. 第六章: SEO与交互指标 二

    上一篇文章地址 5. 提升用户参与度 提高用户参与度不仅有利于SEO,还能增加转化率和用户留存. 5.1 内容结构优化 使用吸引人的标题和小标题: 使用数字列表.问题形式或"如何" ...

  10. PyYaml简单学习

    YAML是一种轻型的配置文件的语言,远比JSON格式方便,方便人类读写,它通过缩进来表示结构,很具有Python风格. 安装:pip insall pyyaml YAML语法 文档 YAML数据流是0 ...