考研伴侣App完整开发记录
项目概述
考研伴侣是一个基于 Vue 3 + Vue Router + Vite + Tailwind CSS 构建的纯前端学习规划应用,专为考研学子设计。应用采用现代化的玻璃拟态(Glassmorphism)设计风格,支持深色/浅色模式切换,所有数据通过 LocalStorage 实现持久化存储。
GitHub 仓库:https://github.com/dafenqirunrunrun/love-study-app
技术栈
| 技术 |
用途 |
| Vue 3 |
前端框架(Composition API) |
| Vue Router 4 |
单页面应用路由 |
| Vite 5 |
构建工具 |
| Tailwind CSS |
原子化CSS框架 |
| LocalStorage |
数据持久化存储 |
| JavaScript (ES6+) |
编程语言 |
核心功能模块
1. 首页概览
1.1 目标倒计时
支持自定义目标名称和日期,从硬编码改为响应式设置:
1 2 3 4 5 6 7 8 9 10 11 12 13
| const countdownSettings = ref({ eventName: '考研初试', targetDate: '2025-12-21' })
const countdownDays = computed(() => { const target = new Date(countdownSettings.value.targetDate) const today = new Date() const diff = target - today return Math.max(0, Math.ceil(diff / (1000 * 60 * 60 * 24))) })
|
用户可在设置中自定义目标名称(考研初试、面试、答辩等)和目标日期,首页实时显示倒计时天数。
1.2 今日任务时间轴
显示当日待办任务,支持优先级标记:
1 2 3 4 5 6 7 8
| <!-- 任务时间轴 --> <div class="timeline-item" v-for="(task, index) in todayTasks" :key="task.id || index" :class="['priority-' + (task.priority || 'normal')]"> <div class="timeline-dot"></div> <span class="task-text">{{ task.text }}</span> </div>
|
1.3 统计数据卡片
四个核心统计卡片:
- 今日专注:显示当日专注总时长
- 今日打卡:显示当日习惯打卡数量
- 完成任务:显示已完成/总任务数
- 当前积分:显示用户积分余额
1.4 展开更多区域
包含三个小组件:
- 每日一句:励志语录展示
- 本周挑战:连续打卡和专注时长进度条
- 学习记录:连续学习天数和总学习天数
⚠️ 问题修复:本周挑战和学习记录原本是硬编码数据,改为 LocalStorage 存储,确保初始化时可以正确重置。
2. 任务管理
任务系统支持:
- ✅ 创建/编辑/删除任务
- ✅ 设置任务优先级(高/中/普通)
- ✅ 设置截止日期
- ✅ 标记任务分类(数学、英语、政治、专业课)
- ✅ 一键完成任务
- ✅ 筛选(全部/进行中/已完成)
- ✅ 搜索功能
- ✅ 撤销删除
3. 番茄钟专注
3.1 核心功能
1 2 3 4 5 6 7
| const focusSettings = ref({ focus: 25, shortBreak: 5, longBreak: 15, goal: 8 })
|
- ⏱️ 专注计时:25分钟标准番茄钟(可自定义1-60分钟)
- ☕ 休息提醒:短休息5分钟,长休息15分钟
- 📊 专注统计:记录每次专注时长和完成次数
- 🔔 音效提示:开始/结束/休息提醒
3.2 白噪音环境音
内置6种环境音效:
- 🌧️ 雨声
- 🌊 海浪
- ☕ 咖啡厅
- 🚂 火车
- 🔥 壁炉
- 🌿 森林
4. 习惯打卡系统
4.1 核心功能
- 📅 每日习惯追踪
- ✅ 一键打卡(带庆祝动画)
- 🎨 自定义习惯图标和颜色
- 📊 本周完成率环形图
- 🌡️ GitHub风格热力图
4.2 热力图实现
1 2 3 4 5 6 7 8 9 10 11 12 13
| const heatmapData = computed(() => { const data = {} const today = new Date() for (let i = 364; i >= 0; i--) { const date = new Date(today) date.setDate(date.getDate() - i) const dateStr = date.toISOString().split('T')[0] const checkins = checkinHistory.value.filter(c => c.date === dateStr).length data[dateStr] = Math.min(checkins, 4) } return data })
|
5. 日历视图
5.1 任务密度可视化
每个日期格子通过背景色深浅表示任务密度:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const getDensityLevel = (date) => { const dateStr = date.toISOString().split('T')[0] const taskCount = tasks.value.filter(t => { const taskDate = t.date || t.createdAt?.split('T')[0] return taskDate === dateStr }).length if (taskCount === 0) return 'none' if (taskCount <= 2) return 'low' if (taskCount <= 4) return 'medium' if (taskCount <= 6) return 'high' return 'full' }
|
密度级别对应5种背景颜色,从浅到深表示任务数量由少到多。
6. 数据统计
6.1 周对比箭头
1 2 3 4 5 6 7 8 9 10 11 12 13
| const comparison = computed(() => { const thisWeek = thisWeekFocus.value const lastWeek = lastWeekFocus.value if (lastWeek === 0) return { percent: 0, direction: 'up' } const change = ((thisWeek - lastWeek) / lastWeek) * 100 return { percent: Math.abs(Math.round(change)), direction: change >= 0 ? 'up' : 'down' } })
|
6.2 统计图表
- 📈 专注时长趋势图
- 📊 任务分类饼图
- 🔥 连续学习天数统计
- 📅 月度热力图
7. 积分中心
7.1 等级系统
5个等级,从低到高:
| 等级 |
名称 |
所需积分 |
称号 |
| 🥉 1级 |
新手 |
0-99 |
考研新手 |
| 📚 2级 |
学者 |
100-499 |
学习学者 |
| 🎓 3级 |
学霸 |
500-1999 |
考研学霸 |
| 🌟 4级 |
大咖 |
2000-4999 |
学习大咖 |
| 🏆 5级 |
传奇 |
5000+ |
考研传奇 |
7.2 虚拟宠物
养成的虚拟宠物会根据饥饿值和心情值变化:
- 🐱 饥饿值低 → 开心
- 🐱 饥饿值高 → 饿肚子
- 心情值随积分变化
7.3 奖励商店
支持按时间筛选:
8. 设置页面
8.1 目标倒计时设置
1 2 3 4
| 设置 → 目标倒计时 ├── 目标名称:自定义(如:考研初试、面试、答辩) ├── 目标日期:选择具体日期 └── 实时显示:距离目标还有 X 天
|
8.2 番茄钟设置
| 设置项 |
默认值 |
可调范围 |
| 专注时长 |
25分钟 |
1-60分钟 |
| 短休息 |
5分钟 |
1-30分钟 |
| 长休息 |
15分钟 |
1-60分钟 |
| 每日目标 |
8次 |
1-20次 |
8.3 数据管理
| 功能 |
说明 |
| 📤 导出数据 |
导出所有数据到JSON文件 |
| 📥 导入数据 |
从JSON文件导入数据 |
| 🚀 初始化 |
新用户重置所有学习数据 |
⚠️ 初始化说明:初始化会清除所有学习数据(任务、打卡、积分等),但保留基本设置(深色模式、番茄钟设置、倒计时设置)。
8.4 日间/夜间模式
一键切换深色/浅色主题,优化日间模式可见性:
1 2 3 4 5 6 7 8 9
| :global(.dark) .setting-name { color: #fff; }
.setting-name { color: #1f2937; }
|
数据存储结构
LocalStorage 键名对照表
| 键名 |
数据类型 |
说明 |
tasks |
Array |
任务列表 |
focusHistory |
Object |
专注历史记录 |
checkinHistory |
Array |
打卡历史 |
lovePoints |
Number |
当前积分 |
pointsHistory |
Array |
积分变动记录 |
habits |
Array |
习惯列表 |
dailyJournal |
Object |
每日心得 |
journalMood |
Object |
每日心情 |
journalHistory |
Array |
心得历史 |
learningPlans |
Array |
学习计划 |
unlockedBadges |
Array |
已解锁徽章 |
focusSettings |
Object |
番茄钟设置 |
countdownSettings |
Object |
倒计时设置 |
weeklyChallenge |
Object |
本周挑战数据 |
learningStats |
Object |
学习统计数据 |
darkMode |
Boolean |
深色模式开关 |
notificationSettings |
Object |
通知设置 |
遇到的问题与解决方案
问题1:Home.vue 页面空白
错误信息:
1
| TypeError: b.value.filter is not a function
|
原因:focusHistory 在不同页面存储格式不一致
- 其他页面:Object 格式
{ "日期": { minutes, sessions } }
- Home.vue:期望 Array 格式
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12
| const normalizeFocusHistory = (data) => { if (!data) return [] if (Array.isArray(data)) return data return Object.entries(data).map(([date, value]) => ({ date, ...value })) }
const focusHistoryRaw = ref(getFromStorage('focusHistory', {})) const focusHistory = computed(() => normalizeFocusHistory(focusHistoryRaw.value))
|
原因:组件未正确接收 props 和 emit
解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const props = defineProps({ isOpen: { type: Boolean, default: false } })
const emit = defineEmits(['close'])
watch(() => props.isOpen, (newVal) => { isOpen.value = newVal })
const close = () => { isOpen.value = false emit('close') }
|
问题3:初始化后本周挑战和学习记录未清零
原因:这些数据是硬编码在 HTML 模板中的
解决方案:
- 将硬编码改为响应式数据
- 添加 LocalStorage 存储
- 初始化时重置默认值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const weeklyChallenge = ref({ checkinStreak: 0, checkinGoal: 5, focusMinutes: 0, focusGoalMinutes: 300 })
const learningStats = ref({ streakDays: 0, totalDays: 0 })
localStorage.setItem('weeklyChallenge', JSON.stringify({ checkinStreak: 0, checkinGoal: 5, focusMinutes: 0, focusGoalMinutes: 300 })) localStorage.setItem('learningStats', JSON.stringify({ streakDays: 0, totalDays: 0 }))
|
问题4:日间模式下设置页面文字看不清
原因:CSS 样式只有深色模式样式
解决方案:添加浅色模式样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| .setting-item { background: #f9fafb; }
.setting-name { color: #1f2937; }
.setting-desc { color: #6b7280; }
.setting-input { border: 1px solid #d1d5db; background: #fff; color: #1f2937; }
:global(.dark) .setting-item { background: rgba(255, 255, 255, 0.05); }
|
设计亮点
1. 玻璃拟态(Glassmorphism)风格
1 2 3 4 5 6 7 8 9 10 11 12
| .glass-card { background: rgba(255, 255, 255, 0.25); backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.3); box-shadow: 0 8px 32px rgba(31, 38, 135, 0.15); }
.glass-card-intense { background: rgba(255, 255, 255, 0.4); backdrop-filter: blur(20px); border: 1px solid rgba(255, 255, 255, 0.5); }
|
2. 动态渐变背景
1 2 3 4 5 6 7 8 9 10 11
| .animate-gradient-shift { background: linear-gradient(-45deg, #ffecd2, #fcb69f, #ffecd2, #feada6, #f5efef, #a7bed3); background-size: 400% 400%; animation: gradient-shift 15s ease infinite; }
@keyframes gradient-shift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
|
3. 悬浮光晕效果
1 2 3 4 5 6 7 8
| .animate-float { animation: float 8s ease-in-out infinite; }
@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-20px); } }
|
4. 彩色光晕叠加
1 2 3 4 5 6
| <div class="absolute inset-0 -z-5 overflow-hidden"> <div class="absolute top-20 left-20 w-72 h-72 bg-orange-300 rounded-full mix-blend-multiply filter blur-3xl opacity-40 animate-float"></div> <div class="absolute top-40 right-32 w-72 h-72 bg-pink-300 rounded-full mix-blend-multiply filter blur-3xl opacity-40 animate-float-delay"></div> <div class="absolute -bottom-20 left-1/3 w-96 h-96 bg-purple-300 rounded-full mix-blend-multiply filter blur-3xl opacity-40 animate-float"></div> <div class="absolute bottom-40 right-20 w-64 h-64 bg-sky-300 rounded-full mix-blend-multiply filter blur-3xl opacity-30 animate-float-delay"></div> </div>
|
5. 响应式设计
- 📱 移动端:底部固定导航栏
- 🖥️ 桌面端:底部悬浮导航栏
- 📲 适配各种屏幕尺寸
项目结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| love-study-app/ ├── index.html # HTML入口 ├── package.json # 项目配置 ├── vite.config.js # Vite配置 ├── tailwind.config.js # Tailwind配置 └── src/ ├── main.js # Vue应用入口 ├── router/ │ └── index.js # 路由配置 ├── views/ # 页面组件 │ ├── Home.vue # 首页 │ ├── Tasks.vue # 任务管理 │ ├── Focus.vue # 番茄钟 │ ├── Checkin.vue # 习惯打卡 │ ├── Calendar.vue # 日历视图 │ ├── Stats.vue # 数据统计 │ ├── PointsCenter.vue # 积分中心 │ ├── Settings.vue # 设置页面 │ ├── Rewards.vue # 心愿单 │ ├── Journal.vue # 学习心得 │ └── Achievements.vue # 成就徽章 ├── components/ # 公共组件 │ ├── Layout.vue # 主布局 │ ├── CalendarView.vue # 日历组件 │ ├── CircularProgress.vue # 环形进度 │ ├── ConfettiEffect.vue # 庆祝动画 │ ├── MoreMenu.vue # 更多菜单 │ └── ... └── style.css # 全局样式
|
版本历史
v1.0.0 (2026-02-09)
- ✨ 初始版本发布
- 🎨 玻璃拟态UI设计
- 📱 响应式布局
- 🔄 深色/浅色模式
- 💾 LocalStorage持久化
v1.1.0 (2026-02-09)
- 🎯 通用化倒计时设置
- 🚀 新增初始化功能
- 🔧 修复日间模式可见性
- 🐛 修复硬编码数据问题
部署方式
本地开发
1 2 3 4 5 6 7
| npm install
npm run dev
|
生产构建
后续优化方向
参考资料
开发感悟:这是一个完全使用纯前端技术栈构建的学习规划应用,通过 LocalStorage 实现了数据的本地持久化。虽然没有后端支持,但通过合理的数据结构设计和本地存储策略,应用能够满足个人学习规划的全部需求。玻璃拟态的UI设计让应用在保持美观的同时,也提供了良好的用户体验。