项目概述
开发了一个完整的 Todo List 全栈应用,采用前后端分离架构,前端使用原生 JavaScript + jQuery 技术栈,后端基于 Python Flask 框架,数据库使用 SQLite,实现了完整的任务管理功能。
技术架构
前端技术栈
- 原生 JavaScript: 核心业务逻辑
- jQuery 3.x: DOM 操作和 AJAX 请求
- HTML5: 语义化结构
- CSS3: 响应式布局和动画效果
后端技术栈
- Python Flask: 轻量级Web框架
- SQLite: 嵌入式数据库
- RESTful API: 标准化接口设计
- JSON: 数据交换格式
功能设计
核心功能
- 任务创建: 添加新的待办事项
- 任务查看: 显示所有任务列表
- 任务编辑: 修改任务内容和状态
- 任务删除: 移除已完成或不需要的任务
- 状态切换: 标记任务完成/未完成
- 数据持久化: 任务信息保存到数据库
界面特性
- 简洁设计: 清晰的任务展示界面
- 实时更新: 操作后立即反映到界面
- 响应式布局: 适配不同屏幕尺寸
- 友好交互: 直观的用户操作体验
前端实现
JavaScript 核心逻辑
// 任务管理类
class TodoManager {
constructor() {
this.tasks = [];
this.init();
}
// 初始化应用
init() {
this.bindEvents();
this.loadTasks();
}
// 绑定事件处理
bindEvents() {
$('#add-task-btn').on('click', () => this.addTask());
$('#task-input').on('keypress', (e) => {
if (e.which === 13) this.addTask();
});
$(document).on('click', '.delete-btn', (e) => {
this.deleteTask($(e.target).data('id'));
});
$(document).on('change', '.task-checkbox', (e) => {
this.toggleTask($(e.target).data('id'));
});
}
// 添加任务
async addTask() {
const taskText = $('#task-input').val().trim();
if (!taskText) return;
try {
const response = await $.post('/api/tasks', {
text: taskText,
completed: false
});
this.renderTask(response);
$('#task-input').val('');
} catch (error) {
console.error('添加任务失败:', error);
}
}
// 删除任务
async deleteTask(taskId) {
try {
await $.ajax({
url: `/api/tasks/${taskId}`,
method: 'DELETE'
});
$(`[data-id="${taskId}"]`).closest('.task-item').remove();
} catch (error) {
console.error('删除任务失败:', error);
}
}
// 切换任务状态
async toggleTask(taskId) {
try {
const response = await $.ajax({
url: `/api/tasks/${taskId}`,
method: 'PUT',
data: { completed: !this.getTaskById(taskId).completed }
});
this.updateTaskDisplay(response);
} catch (error) {
console.error('更新任务失败:', error);
}
}
// 渲染任务列表
renderTasks(tasks) {
const $taskList = $('#task-list');
$taskList.empty();
tasks.forEach(task => this.renderTask(task));
}
// 渲染单个任务
renderTask(task) {
const taskHtml = `
<div class="task-item ${task.completed ? 'completed' : ''}">
<input type="checkbox" class="task-checkbox"
data-id="${task.id}" ${task.completed ? 'checked' : ''}>
<span class="task-text">${task.text}</span>
<button class="delete-btn" data-id="${task.id}">删除</button>
</div>
`;
$('#task-list').append(taskHtml);
}
}
// 初始化应用
$(document).ready(() => {
new TodoManager();
});
CSS 样式设计
/* 主容器样式 */
.todo-container {
max-width: 600px;
margin: 50px auto;
padding: 20px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
/* 输入区域 */
.input-section {
display: flex;
margin-bottom: 30px;
gap: 10px;
}
#task-input {
flex: 1;
padding: 12px;
border: 2px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
#add-task-btn {
padding: 12px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background 0.3s;
}
#add-task-btn:hover {
background: #0056b3;
}
/* 任务列表 */
.task-item {
display: flex;
align-items: center;
padding: 15px;
border-bottom: 1px solid #eee;
transition: background 0.3s;
}
.task-item:hover {
background: #f8f9fa;
}
.task-item.completed {
opacity: 0.6;
}
.task-item.completed .task-text {
text-decoration: line-through;
}
.task-checkbox {
margin-right: 15px;
}
.task-text {
flex: 1;
font-size: 16px;
}
.delete-btn {
background: #dc3545;
color: white;
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
}
.delete-btn:hover {
background: #c82333;
}
后端实现
Flask API 服务
from flask import Flask, request, jsonify, render_template
import sqlite3
import json
from datetime import datetime
app = Flask(__name__)
# 数据库初始化
def init_db():
conn = sqlite3.connect('todo.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
completed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
conn.close()
# 获取所有任务
@app.route('/api/tasks', methods=['GET'])
def get_tasks():
conn = sqlite3.connect('todo.db')
cursor = conn.cursor()
cursor.execute('SELECT * FROM tasks ORDER BY created_at DESC')
tasks = []
for row in cursor.fetchall():
tasks.append({
'id': row[0],
'text': row[1],
'completed': bool(row[2]),
'created_at': row[3],
'updated_at': row[4]
})
conn.close()
return jsonify(tasks)
# 创建新任务
@app.route('/api/tasks', methods=['POST'])
def create_task():
data = request.get_json() or request.form
text = data.get('text', '').strip()
if not text:
return jsonify({'error': '任务内容不能为空'}), 400
conn = sqlite3.connect('todo.db')
cursor = conn.cursor()
cursor.execute(
'INSERT INTO tasks (text, completed) VALUES (?, ?)',
(text, data.get('completed', False))
)
task_id = cursor.lastrowid
conn.commit()
conn.close()
return jsonify({
'id': task_id,
'text': text,
'completed': data.get('completed', False),
'created_at': datetime.now().isoformat()
}), 201
# 更新任务
@app.route('/api/tasks/<int:task_id>', methods=['PUT'])
def update_task(task_id):
data = request.get_json() or request.form
conn = sqlite3.connect('todo.db')
cursor = conn.cursor()
# 检查任务是否存在
cursor.execute('SELECT * FROM tasks WHERE id = ?', (task_id,))
task = cursor.fetchone()
if not task:
conn.close()
return jsonify({'error': '任务不存在'}), 404
# 更新任务
text = data.get('text', task[1])
completed = data.get('completed', task[2])
cursor.execute(
'UPDATE tasks SET text = ?, completed = ?, updated_at = ? WHERE id = ?',
(text, completed, datetime.now().isoformat(), task_id)
)
conn.commit()
conn.close()
return jsonify({
'id': task_id,
'text': text,
'completed': completed,
'updated_at': datetime.now().isoformat()
})
# 删除任务
@app.route('/api/tasks/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
conn = sqlite3.connect('todo.db')
cursor = conn.cursor()
cursor.execute('DELETE FROM tasks WHERE id = ?', (task_id,))
if cursor.rowcount == 0:
conn.close()
return jsonify({'error': '任务不存在'}), 404
conn.commit()
conn.close()
return jsonify({'message': '任务删除成功'})
# 主页路由
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
init_db()
app.run(debug=True, host='0.0.0.0', port=5000)
项目特色
1. 前后端分离
- 清晰的职责划分
- RESTful API 设计
- 前端专注用户交互,后端专注数据处理
2. 技术选型合理
- 原生 JavaScript 保证性能
- jQuery 简化 DOM 操作
- Flask 轻量级易于开发
- SQLite 零配置数据库
3. 代码组织良好
- 模块化的 JavaScript 类设计
- 清晰的 CSS 样式结构
- 标准的 Flask 路由组织
4. 用户体验优秀
- 实时响应用户操作
- 直观的视觉反馈
- 简洁美观的界面设计
部署与运行
本地开发环境
# 后端启动
pip install flask
python app.py
# 前端访问
http://localhost:5000
目录结构
todo-app/
├── app.py # Flask后端服务
├── todo.db # SQLite数据库
├── templates/
│ └── index.html # 主页模板
├── static/
│ ├── js/
│ │ └── app.js # 前端JavaScript
│ └── css/
│ └── style.css # 样式文件
└── requirements.txt # Python依赖
技术收获与思考
架构设计
- 前后端分离提升了开发效率和可维护性
- RESTful API设计确保了接口的标准化
- 轻量级技术栈降低了项目复杂度
开发体验
- 原生JavaScript提供了更好的性能控制
- jQuery大幅简化了DOM操作和AJAX请求
- Flask的简洁性加快了开发进度
代码质量
- 模块化设计提高了代码复用性
- 异常处理保证了应用的稳定性
- 数据验证确保了数据的完整性
未来优化方向
- 功能扩展: 任务分类、优先级、截止日期
- 性能优化: 分页加载、缓存机制
- 用户系统: 登录注册、多用户支持
- 界面增强: 拖拽排序、批量操作
- 移动适配: PWA支持、离线功能
总结
这个 Todo List 全栈应用成功实现了前后端分离的架构设计,通过合理的技术选型和清晰的代码组织,构建了一个功能完整、用户体验良好的任务管理应用。
项目展示了如何使用经典的Web技术栈构建现代化的应用,为进一步的功能扩展和技术升级奠定了坚实的基础。
脱敏说明:本文所有出现的表名、字段名、接口地址、变量名、IP地址及示例数据等均非真实,仅用于阐述技术思路与实现步骤,示例代码亦非公司真实代码。示例方案亦非公司真实完整方案,仅为本人记忆总结,用于技术学习探讨。
• 文中所示任何标识符并不对应实际生产环境中的名称或编号。
• 示例 SQL、脚本、代码及数据等均为演示用途,不含真实业务数据,也不具备直接运行或复现的完整上下文。
• 读者若需在实际项目中参考本文方案,请结合自身业务场景及数据安全规范,使用符合内部命名和权限控制的配置。Data Desensitization Notice: All table names, field names, API endpoints, variable names, IP addresses, and sample data appearing in this article are fictitious and intended solely to illustrate technical concepts and implementation steps. The sample code is not actual company code. The proposed solutions are not complete or actual company solutions but are summarized from the author's memory for technical learning and discussion.
• Any identifiers shown in the text do not correspond to names or numbers in any actual production environment.
• Sample SQL, scripts, code, and data are for demonstration purposes only, do not contain real business data, and lack the full context required for direct execution or reproduction.
• Readers who wish to reference the solutions in this article for actual projects should adapt them to their own business scenarios and data security standards, using configurations that comply with internal naming and access control policies.版权声明:本文版权归原作者所有,未经作者事先书面许可,任何单位或个人不得以任何方式复制、转载、摘编或用于商业用途。
• 若需非商业性引用或转载本文内容,请务必注明出处并保持内容完整。
• 对因商业使用、篡改或不当引用本文内容所产生的法律纠纷,作者保留追究法律责任的权利。Copyright Notice: The copyright of this article belongs to the original author. Without prior written permission from the author, no entity or individual may copy, reproduce, excerpt, or use it for commercial purposes in any way.
• For non-commercial citation or reproduction of this content, attribution must be given, and the integrity of the content must be maintained.
• The author reserves the right to pursue legal action against any legal disputes arising from the commercial use, alteration, or improper citation of this article's content.Copyright © 1989–Present Ge Yuxu. All Rights Reserved.