导航页开发
2026/3/22大约 3 分钟
问题背景
在项目中,需要在VuePress Theme Hope 的基础上搭建一个导航页,用于快速导航到常用网站和工具。导航页开发过程中使用 Claude Code 平台和 KIMI 大模型辅助开发。
页面结构
导航页采用三栏式布局设计:
┌─────────────────────────────────────────┐
│ 实时时钟 (HH:MM) │
│ ┌───────────────────────────┐ │
│ │ [必应▼] 搜索内容... [🔍] │ │
│ └───────────────────────────┘ │
├─────────────────────────────────────────┤
│ │
│ 导航卡片展示区 │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │GitHub│ │Vue │ │... │ │ │
│ └────┘ └────┘ └────┘ └────┘ │
│ │
├─────────────────────────────────────────┤
│ [开发] [学习] [常用] [收藏] [壁纸] │
└─────────────────────────────────────────┘布局层次
- 顶部区域:实时时钟 + 搜索框(支持搜索引擎切换)
- 中间内容区:导航卡片网格展示(根据底部按钮切换分类)
- 底部按钮栏:5 个功能按钮(毛玻璃效果)
- 弹窗:壁纸偏好选择面板
功能特性
1. 实时时钟
- 页面顶部居中显示当前时间(HH:MM 格式)
- 每秒自动更新
- 暗黑模式自动切换文字颜色
2. 多搜索引擎支持
- 支持必应、谷歌两种搜索引擎
- 点击左侧图标可切换搜索引擎
- 快捷键:Alt+1 切换必应,Alt+2 切换谷歌
- 回车键触发搜索
3. 分类导航
| 分类 | 说明 | 示例网站 |
|---|---|---|
| 开发工具 | 常用开发相关网站 | GitHub、Gitee、Docker、Figma |
| 学习资源 | 技术文档和教程 | Vue.js、React、Node.js、TypeScript |
| 常用网站 | 日常访问的网站 | 知乎、B站、掘金、Stack Overflow |
| 个人收藏 | 博客内部页面 | 个人主页、项目展示、笔记归档 |
4. 壁纸切换功能
- 支持 10 张预设风景壁纸
- 支持恢复默认主题背景
- 选择后自动保存到 localStorage
- 离开导航页自动清理背景
5. 响应式适配
- 桌面端:40vw 宽度布局,5 列卡片网格
- 平板端:60vw 宽度,3 列卡片网格
- 手机端:70-80vw 宽度,2 列卡片网格
技术栈
| 技术 | 用途 |
|---|---|
| Vue 3 Composition API | 组件逻辑编写 |
| VuePress 2 | 静态网站生成 |
| Theme Hope | VuePress 主题 |
| CSS3 backdrop-filter | 毛玻璃效果 |
| CSS Grid | 卡片网格布局 |
| localStorage | 壁纸偏好持久化 |
开发过程
样式隔离方案
问题:导航页的全局 CSS 样式污染了主页,导致主页 Hero 区域和按钮消失。
解决:采用基于路由的动态 body 类名方案:
- 在
client.ts中监听路由变化:
watch(() => route.path, (path) => {
if (path === "/nav/") {
document.body.classList.add("nav-page-active");
} else {
document.body.classList.remove("nav-page-active");
}
})- 所有导航页样式使用
body.nav-page-active前缀:
body.nav-page-active .vp-hero-info-wrapper {
display: none !important;
}
body.nav-page-active .theme-container {
background-image: url('...');
}配置化设计
导航卡片数据通过 Markdown frontmatter 配置,实现数据与组件分离:
---
categories:
- id: dev-tools
name: 开发工具
icon: /assets/icon/icon_develop.png
items:
- name: GitHub
url: https://github.com
icon: https://github.com/favicon.ico
external: true
---组件内使用 usePageFrontmatter 读取配置:
const frontmatter = usePageFrontmatter()
const categories = computed(() => {
return frontmatter.value?.categories || defaultCategories
})壁纸持久化
const STORAGE_KEY = 'nav-page-wallpaper'
// 保存选择
const selectWallpaper = (wpId) => {
currentWallpaper.value = wpId
localStorage.setItem(STORAGE_KEY, wpId)
applyWallpaper(wpId)
}
// 加载保存的设置
const loadWallpaper = () => {
const saved = localStorage.getItem(STORAGE_KEY)
if (saved) {
currentWallpaper.value = saved
applyWallpaper(saved)
}
}页面清理机制
离开导航页时需要清理自定义背景,避免影响其他页面:
onUnmounted(() => {
const themeContainer = document.querySelector('.theme-container')
if (themeContainer) {
themeContainer.style.backgroundImage = ''
document.body.classList.remove('has-custom-wallpaper')
}
})同时路由切换时也进行清理:
watch(() => route.path, (path) => {
if (path !== "/" && path !== "/nav/") {
themeContainer.style.backgroundImage = ''
document.body.classList.remove('has-custom-wallpaper')
}
})关键代码文件
| 文件 | 说明 |
|---|---|
src/.vuepress/components/NavPage.vue | 导航页主组件 |
src/nav/README.md | 导航页配置和数据 |
src/.vuepress/client.ts | 路由监听和 body 类名管理 |
src/.vuepress/styles/index.scss | 导航页样式变量 |