vitepress动态导航
前言
我需要根据动态设置导航。
比如根据不同的路由设置不同的顶部导航。
但是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动态导航的更多相关文章
- Jquery实现动态导航栏和轮播导航栏
动态导航栏和轮播导航栏的实现思想: 利用jquery技术的append()方法和bind()方法实现li标签的添加和点击事件绑定,在利用$getJSON(url,data,function)请求方法实 ...
- 动态导航栏和JavaScript箭头函数
动态导航栏和JavaScript箭头函数 今天我们来写一下动态的导航栏,并且学一下JavaScript的箭头函数等相关问题. 样式如下所示: html中执行代码如下所示: <!DOCTYPE h ...
- 纯CSS3实现动态导航栏目
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- HTML和CSS设置动态导航以及CSS中伪元素的简单说明
HTML页面代码: <!DOCTYPE html> <html> <head> <title>Test</title> <meta c ...
- 巧妙使用checkbox制作纯css动态导航栏
前提:很多时候.我们的网页都需要一个垂直的导航栏.可以分类.有分类.自然就有展开.关闭的功能.你还在使用jquery操作dom来制作吗?那你就out了! 方案:使用checkbox 的 checked ...
- vue-router 动态导航 router-link :to属性
经常碰到这类需求,从后台获取数据后再前程连接,参数id动态获取 <el-row v-for="item in Travels"> <el-col :span=&q ...
- jsp动态导航栏
站点页面的导航栏是从数据库中生成出来的,所以在界面上展示导航栏时,要从数据库中读取出来,但不能每次显示一个页面都从数据库中读.这样就非常浪费性能.应该考虑把导航栏放到一个缓存中.如:session.a ...
- vue+el-menu+vue-router实现动态导航条
导航栏组件template <template> <div class="sidebar"> <el-menu unique-opened :defa ...
- 第六章节 BJROBOT 动态导航壁障
导航前说明:一定要确保你小车在构建好地图的基础上进行! 1.把小车平放在你想要构建地图区域的地板上,打开资料里的虚拟机,打开一个终端, ssh 过去主控端启动 roslaunch znjrobot b ...
- vue、element-ui 依权限动态导航 v-for、v-if
在管理后台需要按用户权限展示不同导航菜单时,我们需要从后端请求数据来进行菜单渲染. 但由于v-for与v-if不能在同一标签内使用(存在性能问题:v-for 具有比 v-if 更高的优先级,意味着 v ...
随机推荐
- 持续集成cicd和devops
什么是 cicd,devops DevOps是一种思想,是一种文化,主要强调软件开发测试运维的一体化,目标是减少各个部门之间的沟通成本从而实现软件的快速高质量的发布.cicd是指持续集成发布部署,是一 ...
- leetcode001 两数之和
问题描述:两数之和 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标. 你可以假设每种输入只会对应一个答 ...
- issue: java.lang.NoClassDefFoundError: javax/el/ELManager
问题描述: Context initialization failed org.springframework.beans.factory.BeanCreationException: Error c ...
- 关于php里怎么把字符串‘false’转成boolean的false
都知道php里类型转换常用的是settype($str,'boolean')和(bool)$str 但是,他们将字符串'false'和'true'转成boolean后都是true,可能这不是我们需要的 ...
- Git错误,fatal: refusing to merge unrelated histories
错误:fatal: refusing to merge unrelated histories 中文意思就是拒绝合并不相关的历史, 解决 出现这个问题的最主要原因还是在于本地仓库和远程仓库实际上是独立 ...
- OpenStack 全套搭建部署指南(基于 Kolla-Ansible)
一.环境准备 1. 硬件要求 控制节点:至少 4 核 CPU,8GB 内存,100GB 磁盘(推荐 SSD). 计算节点:根据虚拟机需求调整,建议 8 核 CPU,16GB 内存,200GB+ 磁盘. ...
- tar命令打包指定目录及其文件,而不包括其上级目录
想指定将/var目录下的log目录及其文件打包到当前目录,在压缩包解压时不包括/var目录,可使用如下方式: tar -zcvf log_bak.tar.gz -C /var/ log # 注意log ...
- coreybutler/nvm-windows 简单使用
目录 nvm是什么 安装 简单命令 nvm是什么 Windows电脑node.js管理器.可以方便node.js的安装与切换. 最新版本1.1.11 coreybutler/nvm-windows 有 ...
- 解决C盘根目录不能创建文件,只能创建文件夹问题
转载:https://blog.csdn.net/xinke453/article/details/7496545 解决方法 用管理员运行cmd 输入 icacls c:\ /setintegrity ...
- 一站式搭建交友平台-交友系统源码-支持H5小程序+带安装说明+可封装APP-交友网站系统平台搭建
诺诺婚恋交友系统 1.系统基于TP6+Uni-app框架开发:客户移动端采用uni-app开发,管理后台TH6开发. 2.系统支持微信公众号端.微信小程序端.H5端.PC端多端账号同步,可快速打包生成 ...