从零开始打造一个「个人番茄钟与任务管理」Web 应用
从零开始打造一个「个人番茄钟与任务管理」Web 应用
看完就能上手
🎯 适合人群
- 掌握基础 HTML/CSS/JavaScript
- 了解 Vue/Node.js 基本语法
- 想通过完整项目打通前后端、提升工程化思维的开发者
📦 完整源码
文末附 GitHub 仓库地址,Star 收藏防丢失,跟着写一遍胜过看十篇理论。
📖 项目介绍
这是一个全栈轻量级个人效率工具,核心解决三个痛点:
- 专注计时:25分钟工作 + 5分钟休息的番茄钟,自动循环切换。
- 任务管理:支持待办任务的增删改查、完成状态标记、与当前番茄钟绑定。
- 数据持久化:本地刷新不丢失,支持一键导出备份。
🛠 技术栈
- 前端:Vue 3 (Composition API) + Vite + TailwindCSS
- 后端:Node.js + Express + better-sqlite3
- 部署:Docker + Nginx + PM2
🖥 最终效果
- 响应式深色/浅色 UI
- 流畅的倒计时动画
- 实时同步任务状态
- 支持本地与云端双模式切换
- 整体打包体积 < 50KB,首屏加载 < 1s
🛠 环境搭建
我们采用前后端分离架构,先初始化项目目录并安装核心依赖。
# 创建项目根目录
mkdir pomodoro-app && cd pomodoro-app
# 前端初始化
npm create vite@latest client -- --template vue-ts
cd client && npm install && npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
cd ..
# 后端初始化
mkdir server && cd server
npm init -y
npm install express cors better-sqlite3 dotenv
npm install -D nodemon typescript ts-node @types/express @types/node
✅ 配置提示
在 server/tsconfig.json 中开启 "esModuleInterop": true,确保 better-sqlite3 正常导入。前后端均配置 tsconfig.json 避免类型漂移。
🧩 核心功能实现
🔹 功能 1:番茄钟计时器核心逻辑
需求分析:需要实现倒计时、暂停/继续、工作/休息自动切换,且组件卸载时自动清理定时器,防止内存泄漏。
代码文件:src/composables/usePomodoro.ts
import { ref, onUnmounted } from 'vue'
export function usePomodoro() {
const timeLeft = ref(25 * 60)
const isRunning = ref(false)
const mode = ref<'work' | 'break'>('work')
let timer: number | null = null
const toggle = () => {
isRunning.value ? pause() : start()
}
const start = () => {
if (timer) return
isRunning.value = true
timer = window.setInterval(() => {
timeLeft.value--
if (timeLeft.value <= 0) {
mode.value = mode.value === 'work' ? 'break' : 'work'
timeLeft.value = mode.value === 'work' ? 25 * 60 : 5 * 60
pause()
}
}, 1000)
}
const pause = () => {
if (timer) {
clearInterval(timer)
timer = null
isRunning.value = false
}
}
const reset = () => {
pause()
mode.value = 'work'
timeLeft.value = 25 * 60
}
onUnmounted(() => pause()) // 组件销毁时清理定时器
return { timeLeft, isRunning, mode, toggle, pause, reset }
}
💡 亮点:采用 Composable 封装,状态与视图解耦,可复用到其他页面。
🔹 功能 2:任务列表增删改与状态管理
需求分析:提供任务数组响应式管理,支持添加新任务、切换完成状态、删除,并实时过滤“进行中”任务。
代码文件:src/components/TaskList.vue(核心逻辑片段)
<script setup lang="ts">
import { ref, computed } from 'vue'
interface Task {
id: number
title: string
completed: boolean
}
const tasks = ref<Task[]>([])
const newTask = ref('')
const activeTasks = computed(() => tasks.value.filter(t => !t.completed))
const completedCount = computed(() => tasks.value.filter(t => t.completed).length)
const addTask = () => {
if (!newTask.value.trim()) return
tasks.value.push({ id: Date.now(), title: newTask.value, completed: false })
newTask.value = ''
}
const toggleTask = (id: number) => {
const task = tasks.value.find(t => t.id === id)
if (task) task.completed = !task.completed
}
const removeTask = (id: number) => {
tasks.value = tasks.value.filter(t => t.id !== id)
}
</script>
💡 亮点:利用 computed 自动派生状态,避免手动维护冗余变量;配合 Tailwind 可快速实现交互动画。
🔹 功能 3:后端 API 与 SQLite 数据持久化
需求分析:提供 RESTful API 接收前端任务数据,使用轻量级 SQLite 实现本地持久化,支持跨域请求与基础错误处理。
代码文件:server/src/index.ts
import express from 'express'
import cors from 'cors'
import Database from 'better-sqlite3'
const app = express()
const db = new Database('tasks.db')
app.use(cors())
app.use(express.json())
// 初始化表
db.prepare(`
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
completed INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`).run()
app.get('/tasks', (_, res) => {
const tasks = db.prepare('SELECT * FROM tasks ORDER BY created_at DESC').all()
res.json(tasks.map(t => ({ ...t, completed: Boolean(t.completed) })))
})
app.post('/tasks', (req, res) => {
const { title } = req.body
if (!title) return res.status(400).json({ error: 'Title required' })
const info = db.prepare('INSERT INTO tasks (title) VALUES (?)').run(title)
res.status(201).json({ id: info.lastInsertRowid, title, completed: false })
})
app.put('/tasks/:id', (req, res) => {
const { completed } = req.body
db.prepare('UPDATE tasks SET completed = ? WHERE id = ?').run(Number(completed), Number(req.params.id))
res.json({ success: true })
})
app.listen(3000, () => console.log('🚀 Server running on http://localhost:3000'))
💡 亮点:better-sqlite3 同步 API 性能更高,代码更简洁;生产环境建议替换为异步驱动或 PostgreSQL。
🚀 项目部署
我们将前后端打包,使用 Docker Compose 一键部署到云服务器(如阿里云/腾讯云)。
代码文件:docker-compose.yml
version: '3.8'
services:
backend:
build: ./server
ports:
- "3000:3000"
environment:
- NODE_ENV=production
volumes:
- db-data:/app/data
restart: always
frontend:
build: ./client
ports:
- "80:80"
depends_on:
- backend
restart: always
volumes:
db-data:
📦 配合 Dockerfile:后端使用 node:20-alpine 多阶段构建,前端使用 nginx:alpine 托管静态文件。执行 docker compose up -d 即可完成生产级部署,自带健康检查与自动重启。
🔮 扩展方向(你的下一步)
这个项目已经具备完整的工程骨架,你可以按以下路线持续迭代,打造个人作品集:
- 用户系统:接入 JWT + 邮箱登录,实现多端数据同步。
- PWA 支持:添加
vite-plugin-pwa,实现离线可用与桌面安装。 - 数据统计:集成 Chart.js,展示每日专注时长折线图、任务完成率雷达图。
- AI 增强:调用大模型 API,实现“智能任务拆解”、“专注力语音提醒”。
- CI/CD 流水线:配置 GitHub Actions,代码 push 后自动测试、构建、部署。
🤝 写在最后
实战项目是打破“收藏等于学会”魔咒的最佳武器。这篇文章只展示了核心骨架,完整可运行代码、UI 主题切换逻辑、环境变量配置、详细部署文档已开源至 GitHub。
📌 如何获取完整源码?
关注本公众号/专栏,回复关键词 番茄钟 即可获取 GitHub 仓库直链。已 Star 的同学可在 Issues 提交你的优化 PR,我会亲自 Code Review 并合并。
💬 互动话题
你在做项目时最常卡在哪个环节?环境配置、状态管理还是部署?留言区告诉我,下期针对性拆解。
⭐ 星标/订阅
每周更新一个“从零到一”高转化实战项目,不卷理论,只写能跑、能部署、能写进简历的代码。
下一期预告:《手把手教你用 Rust + WebAssembly 给前端提速 300% 的完整实战》
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)