在这篇博客中,我将带大家一步步构建一个简单的待办事项列表应用,使用到的技术栈主要是 React,并结合 umi 框架进行项目搭建,以及借助 antd 库来实现美观的 UI 界面。
一、项目构思
待办事项列表是一个常见的应用场景,用户需要能够方便地添加新的待办事项、对已有的事项进行编辑和删除操作。每个待办事项包含多个重要信息,比如创建时间、具体事项内容、是否完成的状态、截止时间(若未完成)以及完成时间(若已完成)。
演示图:
为了实现这些功能,我们可以从以下几个方面来考虑:
数据结构设计
首先要确定待办事项的数据结构,在 JavaScript 中,我们可以用对象来表示一个待办事项,例如:
{
id: 1, // 每个事项独一无二的标识,方便后续操作
createTime: new Date(), // 创建时间
task: '完成工作报告', // 具体事项
isCompleted: false, // 是否完成
dueTime: new Date('2024-12-10'), // 截止时间(假设)
completeTime: null // 完成时间,初始化为null
}
这里给每个待办事项定义了一个 id,方便在列表中准确地找到并操作特定的事项。
功能模块划分
- 添加事项模块:提供一个输入框让用户输入具体事项内容,再设置相关按钮来触发添加操作,添加时自动生成创建时间,并可根据用户需求设置截止时间(也可后续再编辑)。
- 编辑事项模块:当用户点击某个待办事项的编辑按钮时,弹出一个对话框或者进入编辑页面,允许用户修改具体事项内容、截止时间等信息。
- 删除事项模块:在每个待办事项旁边设置一个删除按钮,点击即可从列表中删除该事项。
- 事项列表展示模块:将所有的待办事项以列表的形式展示出来,清晰地显示各项信息,如创建时间、具体事项、是否完成状态等,对于已完成的事项,不显示截止时间,而是显示完成时间。
用户交互设计
用户与应用的交互应该简洁明了。例如,添加事项后能立即在列表中看到新添加的内容;点击编辑按钮能顺利进入编辑状态并保存修改后的结果;删除操作要有确认提示,防止误删。
二、项目环境配置与依赖项安装
安装 umi 框架
首先确保你的电脑已经安装了 Node.js,然后在命令行中执行以下命令来创建一个 umi 项目:
npx create-umi@latest my-todo-list
这里 my-todo-list 是我们项目的名称,你可以根据自己的喜好进行修改。
执行完上述命令后,会自动安装相关的依赖项并创建项目的基本结构。
安装 antd 库
进入项目目录(cd my-todo-list),然后执行以下命令来安装 antd 库:
npm install antd
antd 是一个优秀的 React UI 组件库,它提供了丰富的组件,可以让我们快速搭建出美观且功能齐全的界面。
配置 less-loader(用于 antd 样式定制)
因为 antd 的样式是基于 less 编写的,所以我们需要在项目中配置 less-loader 来正确加载样式。
首先安装 less 和 less-loader:
npm install less less-loader --save-dev
然后在项目的 webpack.config.js 文件(如果没有,可以在 umi 项目根目录下创建一个)中进行如下配置(以下是示例配置,具体可能需要根据项目实际情况调整):
module.exports = {
module: {
rules: [
{
test: /.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
}
]
}
};
这样就完成了项目的基本环境配置和主要依赖项的安装,可以开始编写具体的代码来实现待办事项列表的功能了。
三、编写代码实现功能
1. 创建数据存储文件
在项目的 src 目录下创建一个名为 todoData.js 的文件,用于存储待办事项的数据。
// todoData.js
let todoList = [];
export const addTodo = (todo) => {
todo.id = Date.now(); // 用当前时间戳作为id,确保唯一性
todo.createTime = new Date();
todoList.push(todo);
};
export const editTodo = (id, updatedTodo) => {
const index = todoList.findIndex(todo => todo.id === id);
if (index!== -1) {
todoList[index] = {...todoList[index],...updatedTodo };
}
};
export const deleteTodo = (id) => {
todoList = todoList.filter(todo => todo.id!== id);
};
export const getTodoList = () => todoList;
在这个文件中,我们定义了一个数组 todoList 来存储所有的待办事项。然后提供了几个函数来实现添加、编辑、删除待办事项以及获取待办事项列表的功能。
addTodo函数:接收一个待办事项对象作为参数,给它添加id和createTime属性后,将其添加到todoList数组中。editTodo函数:根据传入的id找到对应的待办事项,然后用更新后的待办事项对象替换原来的那个。deleteTodo函数:根据id过滤掉要删除的待办事项,从而实现从列表中删除的操作。getTodoList函数:简单地返回当前的todoList数组,以便在其他组件中获取待办事项列表进行展示。
2. 创建待办事项列表组件
在 src 目录下创建一个名为 TodoList.js 的组件文件。
// TodoList.js
import React, { useState, useEffect } from 'react';
import * as data from './todoData.js';
import { Table, Button, Modal, Input, DatePicker } from 'antd';
const { Column } = Table;
const TodoList = () => {
const [todoList, setTodoList] = useState([]);
const [isEditing, setIsEditing] = useState(false);
const [editingTodo, setEditingTodo] = useState({});
const [visible, setVisible] = useState(false);
useEffect(() => {
const list = data.getTodoList();
setTodoList(list);
}, []);
const handleAddTodo = () => {
setVisible(true);
};
const handleSaveTodo = () => {
const newTodo = {
task: editingTodo.task,
isCompleted: false,
dueTime: editingTodo.dueTime
};
data.addTodo(newTodo);
setVisible(false);
setIsEditing(false);
setEditingTodo({});
setTodoList(data.getTodoList());
};
const handleEditTodo = (id) => {
const todo = todoList.find(todo => todo.id === id);
setIsEditing(true);
setEditingTodo(todo);
setVisible(true);
};
const handleDeleteTodo = (id) => {
Modal.confirm({
title: '确认删除',
content: '确定要删除该待办事项吗?',
onOk: () => {
data.deleteTodo(id);
setTodoList(data.getTodoList());
}
});
};
const columns = [
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
render: (text) => text.toLocaleString()
},
{
title: '具体事项',
dataIndex: 'task',
key: 'task'
},
{
title: '是否完成',
dataIndex: 'isCompleted',
key: 'isCompleted',
render: (text) => text? '已完成' : '未完成'
},
{
title: '截止时间',
dataIndex: 'dueTime',
key: 'dueTime',
render: (text, record) => record.isCompleted? '' : text.toLocaleString()
},
{
title: '完成时间',
dataIndex: 'completeTime',
key: 'completeTime',
render: (text) => text? text.toLocaleString() : ''
},
{
title: '操作',
key: 'action',
render: (text, record) => (
<span>
{!record.isCompleted && <Button type="link" onClick={() => handleEditTodo(record.id)}>编辑</Button>}
<Button type="link" onClick={() => handleDeleteTodo(record.id)}>删除</Button>
</span>
)
}
];
return (
<div>
<Button type="primary" onClick={handleAddTodo}>添加待办事项</Button>
<Table dataSource={todoList} columns={columns} />
<Modal
title={isEditing? '编辑待办事项' : '添加待办事项'}
visible={visible}
onOk={handleSaveTodo}
onCancel={() => {
setVisible(false);
setIsEditing(false);
setEditingTodo({});
}}
>
<Input
placeholder="请输入具体事项"
value={editingTodo.task}
onChange={(e) => setEditingTodo({...editingTodo, task: e.target.value })}
/>
<DatePicker
placeholder="请选择截止时间"
value={editingTodo.dueTime}
onChange={(date) => setEditingTodo({...editingTodo, dueTime: date })}
/>
</Modal>
</div>
);
};
export default TodoList;
下面来详细讲解一下这个组件的代码:
-
首先导入了必要的 React 钩子函数
useState和useEffect,以及从todoData.js文件中导入了操作待办事项数据的函数,还从 antd 库中导入了需要用到的组件,如Table、Button、Modal、Input、DatePicker等。 -
在组件内部,使用
useState钩子函数定义了几个状态:todoList:用于存储从todoData.js获取到的待办事项列表,初始值为空数组,通过useEffect钩子在组件挂载时获取并设置初始值。isEditing:用于标识当前是否处于编辑某个待办事项的状态,初始值为false。editingTodo:用于存储正在编辑的待办事项对象,初始值为空对象。visible:用于控制添加 / 编辑待办事项的模态框是否可见,初始值为false。
-
useEffect钩子函数:在组件挂载时,调用getTodoList函数获取待办事项列表,并将其设置为todoList状态的值,这样组件一开始就能展示已有的待办事项。 -
handleAddTodo函数:当点击 “添加待办事项” 按钮时,设置visible状态为true,从而显示添加待办事项的模态框。 -
handleSaveTodo函数:在添加或编辑待办事项后,点击模态框的 “确定” 按钮时调用。它首先根据当前editingTodo状态构建一个新的待办事项对象(如果是编辑,这里的editingTodo已经包含了更新后的信息),然后调用addTodo函数添加新事项(如果是编辑则是更新操作),接着隐藏模态框,重置编辑相关的状态,并重新获取最新的待办事项列表设置给todoList状态。 -
handleEditTodo函数:当点击某个待办事项的 “编辑” 按钮时,根据传入的id找到对应的待办事项,设置isEditing、editingTodo和visible状态,从而进入编辑模式并显示模态框。 -
handleDeleteTodo函数:当点击某个待办事项的 “删除” 按钮时,弹出一个确认对话框,在用户确认后,调用deleteTodo函数删除对应的待办事项,并重新获取最新的待办事项列表设置给todoList状态。 -
columns数组:定义了用于展示待办事项列表的表格列信息。每一列对应一个待办事项的属性,通过render函数可以对属性值进行格式化展示,比如将日期格式化为本地字符串格式,根据isCompleted状态显示不同的文本等。
3. 在入口文件中使用待办事项列表组件
最后,在项目的入口文件(通常是 src/index.js)中引入并使用 TodoList.js 组件。
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList.js';
import 'antd/dist/antd.css';
ReactDOM.render(
<TodoList />,
document.getElementById('root')
);
这里首先导入了 React、ReactDOM、TodoList 组件以及 antd 的样式文件。然后使用 ReactDOM.render 函数将 TodoList 组件渲染到 id 为 root 的 DOM 元素上,这样我们的待办事项列表应用就可以在浏览器中正常展示并使用了。
通过以上步骤,我们就成功地使用 React、umi 框架和 antd 库构建了一个简单的待办事项列表应用,用户可以方便地添加、编辑和删除待办事项,并能清晰地查看各项相关信息。当然,这只是一个基础的实现,你还可以根据自己的需求进一步扩展和优化这个应用,比如添加更多的筛选功能、设置提醒功能等等。