实战项目:待办事项小程序(上)- 需求分析和页面设计
🚀 理论学了这么多,是时候做个真正的项目了!我们来做一个待办事项小程序
项目介绍
我们要做一个简单而实用的待办事项小程序,用户可以:
- 添加待办事项
- 标记完成状态
- 编辑和删除事项
- 按分类管理
- 数据本地存储
这个项目会用到我们前面学过的所有知识点!
需求分析
功能需求
1. 核心功能
- ✅ 添加新的待办事项
- ✅ 查看待办事项列表
- ✅ 标记事项为完成/未完成
- ✅ 编辑事项内容
- ✅ 删除事项
2. 扩展功能
- ✅ 事项分类(工作、生活、学习等)
- ✅ 优先级设置(高、中、低)
- ✅ 截止日期设置
- ✅ 搜索功能
- ✅ 统计功能
3. 数据管理
- ✅ 本地存储(使用 uni.storage)
- ✅ 数据导入导出
- ✅ 数据备份
页面结构
待办事项小程序
├── 首页(待办列表)
├── 添加/编辑页面
├── 分类管理页面
├── 统计页面
└── 设置页面
技术选型
前端技术
- 框架:UniApp + Vue.js
- 样式:SCSS + Flex布局
- 图标:Unicode图标 + 自定义图标
- 动画:CSS3动画 + UniApp动画API
数据存储
- 本地存储:uni.setStorageSync / uni.getStorageSync
- 数据结构:JSON格式
开发工具
- IDE:HBuilderX
- 调试:浏览器 + 微信开发者工具
数据结构设计
待办事项数据结构
javascript
const todoItem = {
id: 'todo_1640995200000', // 唯一ID(时间戳)
title: '完成UniApp教程', // 事项标题
description: '学习UniApp开发', // 详细描述
category: 'study', // 分类
priority: 'high', // 优先级:high/medium/low
dueDate: '2024-12-20', // 截止日期
completed: false, // 是否完成
createdAt: '2024-12-15 10:30', // 创建时间
updatedAt: '2024-12-15 10:30', // 更新时间
completedAt: null // 完成时间
}
分类数据结构
javascript
const categories = [
{ id: 'work', name: '工作', color: '#ff6b6b', icon: '💼' },
{ id: 'life', name: '生活', color: '#4ecdc4', icon: '🏠' },
{ id: 'study', name: '学习', color: '#45b7d1', icon: '📚' },
{ id: 'health', name: '健康', color: '#96ceb4', icon: '💪' },
{ id: 'other', name: '其他', color: '#feca57', icon: '📝' }
]
页面设计
1. 首页(待办列表)
页面功能:
- 显示待办事项列表
- 快速标记完成状态
- 搜索和筛选
- 添加新事项
页面布局:
vue
<template>
<view class="todo-home">
<!-- 头部统计 -->
<view class="header-stats">
<view class="stat-item">
<text class="stat-number">\{\{ totalTodos \}\}</text>
<text class="stat-label">总计</text>
</view>
<view class="stat-item">
<text class="stat-number">\{\{ pendingTodos \}\}</text>
<text class="stat-label">待完成</text>
</view>
<view class="stat-item">
<text class="stat-number">\{\{ completedTodos \}\}</text>
<text class="stat-label">已完成</text>
</view>
</view>
<!-- 搜索栏 -->
<view class="search-bar">
<input
v-model="searchKeyword"
placeholder="搜索待办事项..."
class="search-input"
/>
<button class="filter-btn" @click="showFilter">筛选</button>
</view>
<!-- 分类标签 -->
<scroll-view scroll-x class="category-tabs">
<view
class="category-tab"
:class="{ active: selectedCategory === 'all' }"
@click="selectCategory('all')"
>
全部
</view>
<view
v-for="category in categories"
:key="category.id"
class="category-tab"
:class="{ active: selectedCategory === category.id }"
@click="selectCategory(category.id)"
>
\{\{ category.icon \}\} \{\{ category.name \}\}
</view>
</scroll-view>
<!-- 待办列表 -->
<scroll-view scroll-y class="todo-list">
<view
v-for="todo in filteredTodos"
:key="todo.id"
class="todo-item"
:class="{ completed: todo.completed }"
>
<!-- 完成状态 -->
<view
class="todo-checkbox"
:class="{ checked: todo.completed }"
@click="toggleTodo(todo.id)"
>
<text v-if="todo.completed" class="check-icon">✓</text>
</view>
<!-- 事项内容 -->
<view class="todo-content" @click="editTodo(todo)">
<text class="todo-title">\{\{ todo.title \}\}</text>
<text v-if="todo.description" class="todo-desc">\{\{ todo.description \}\}</text>
<view class="todo-meta">
<text class="todo-category">\{\{ getCategoryName(todo.category) \}\}</text>
<text v-if="todo.dueDate" class="todo-date">\{\{ todo.dueDate \}\}</text>
<text class="todo-priority" :class="todo.priority">\{\{ getPriorityText(todo.priority) \}\}</text>
</view>
</view>
<!-- 操作按钮 -->
<view class="todo-actions">
<button class="action-btn edit" @click="editTodo(todo)">编辑</button>
<button class="action-btn delete" @click="deleteTodo(todo.id)">删除</button>
</view>
</view>
<!-- 空状态 -->
<view v-if="filteredTodos.length === 0" class="empty-state">
<text class="empty-icon">📝</text>
<text class="empty-text">暂无待办事项</text>
<button class="add-first-btn" @click="addTodo">添加第一个待办</button>
</view>
</scroll-view>
<!-- 添加按钮 -->
<view class="fab" @click="addTodo">
<text class="fab-icon">+</text>
</view>
</view>
</template>
2. 添加/编辑页面
页面功能:
- 输入事项标题和描述
- 选择分类和优先级
- 设置截止日期
- 保存或更新事项
表单设计:
vue
<template>
<view class="todo-form">
<view class="form-header">
<button class="cancel-btn" @click="goBack">取消</button>
<text class="form-title">\{\{ isEdit ? '编辑待办' : '新增待办' \}\}</text>
<button class="save-btn" @click="saveTodo" :disabled="!canSave">保存</button>
</view>
<view class="form-content">
<!-- 标题输入 -->
<view class="form-group">
<text class="form-label">标题 *</text>
<input
v-model="formData.title"
placeholder="请输入待办事项标题"
class="form-input"
maxlength="50"
/>
</view>
<!-- 描述输入 -->
<view class="form-group">
<text class="form-label">描述</text>
<textarea
v-model="formData.description"
placeholder="请输入详细描述(可选)"
class="form-textarea"
maxlength="200"
/>
</view>
<!-- 分类选择 -->
<view class="form-group">
<text class="form-label">分类</text>
<picker
:range="categoryOptions"
range-key="name"
:value="categoryIndex"
@change="onCategoryChange"
>
<view class="picker-input">
<text>\{\{ selectedCategory.icon \}\} \{\{ selectedCategory.name \}\}</text>
<text class="arrow">></text>
</view>
</picker>
</view>
<!-- 优先级选择 -->
<view class="form-group">
<text class="form-label">优先级</text>
<view class="priority-options">
<view
v-for="priority in priorityOptions"
:key="priority.value"
class="priority-option"
:class="{ active: formData.priority === priority.value }"
@click="selectPriority(priority.value)"
>
<text class="priority-dot" :class="priority.value"></text>
<text>\{\{ priority.label \}\}</text>
</view>
</view>
</view>
<!-- 截止日期 -->
<view class="form-group">
<text class="form-label">截止日期</text>
<picker
mode="date"
:value="formData.dueDate"
:start="today"
@change="onDateChange"
>
<view class="picker-input">
<text>\{\{ formData.dueDate || '请选择截止日期' \}\}</text>
<text class="arrow">></text>
</view>
</picker>
</view>
</view>
</view>
</template>
样式设计
设计原则
- 简洁明了:界面简洁,操作直观
- 色彩搭配:使用温和的色彩,不同优先级用不同颜色
- 响应式:适配不同屏幕尺寸
- 动画效果:适当的动画提升用户体验
色彩方案
scss
// 主色调
$primary-color: #007aff;
$success-color: #34c759;
$warning-color: #ff9500;
$danger-color: #ff3b30;
// 优先级颜色
$high-priority: #ff3b30;
$medium-priority: #ff9500;
$low-priority: #34c759;
// 分类颜色
$work-color: #ff6b6b;
$life-color: #4ecdc4;
$study-color: #45b7d1;
$health-color: #96ceb4;
$other-color: #feca57;
// 背景色
$bg-color: #f8f9fa;
$card-bg: #ffffff;
$border-color: #e9ecef;
组件样式
scss
// 待办事项卡片
.todo-item {
background: $card-bg;
border-radius: 12px;
padding: 16px;
margin-bottom: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
transition: all 0.3s ease;
&.completed {
opacity: 0.6;
.todo-title {
text-decoration: line-through;
color: #999;
}
}
&:active {
transform: scale(0.98);
}
}
// 复选框
.todo-checkbox {
width: 24px;
height: 24px;
border: 2px solid #ddd;
border-radius: 50%;
margin-right: 12px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&.checked {
background: $success-color;
border-color: $success-color;
.check-icon {
color: white;
font-size: 14px;
font-weight: bold;
}
}
}
// 浮动按钮
.fab {
position: fixed;
right: 20px;
bottom: 20px;
width: 56px;
height: 56px;
background: $primary-color;
border-radius: 28px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0, 122, 255, 0.3);
.fab-icon {
color: white;
font-size: 24px;
font-weight: bold;
}
&:active {
transform: scale(0.95);
}
}
项目文件结构
todo-app/
├── pages/
│ ├── index/ # 首页
│ │ └── index.vue
│ ├── add-todo/ # 添加/编辑页面
│ │ └── add-todo.vue
│ ├── categories/ # 分类管理
│ │ └── categories.vue
│ ├── statistics/ # 统计页面
│ │ └── statistics.vue
│ └── settings/ # 设置页面
│ └── settings.vue
├── components/ # 自定义组件
│ ├── TodoItem.vue # 待办事项组件
│ ├── CategoryPicker.vue # 分类选择器
│ └── PriorityPicker.vue # 优先级选择器
├── utils/ # 工具函数
│ ├── storage.js # 存储工具
│ ├── date.js # 日期工具
│ └── constants.js # 常量定义
├── static/ # 静态资源
│ └── images/
└── styles/ # 全局样式
├── variables.scss # 变量定义
├── mixins.scss # 混合器
└── common.scss # 通用样式
下一步计划
在下一篇文章中,我们将:
- 实现数据管理逻辑
- 完成核心功能开发
- 添加本地存储
- 实现搜索和筛选
- 优化用户体验
小结
今天我们完成了:
- ✅ 项目需求分析
- ✅ 技术选型
- ✅ 数据结构设计
- ✅ 页面结构规划
- ✅ UI设计方案
- ✅ 项目文件结构
设计要点:
- 功能要简单实用
- 界面要简洁美观
- 数据结构要合理
- 代码结构要清晰
下一篇预告
下一篇《实战项目:待办事项小程序(中)- 功能实现和数据处理》,我们将开始编写具体的代码,实现所有核心功能。
好的设计是成功的一半,接下来让我们把设计变成现实!