使用React 实现一个简单的待办事项列表,其中用户可以添加、编辑和删除待办事项,并且可以修改待办事项为已完成。下面是详细的步骤:
配置React开发环境
1. 安装Node.js和npm
React项目依赖于Node.js和npm来管理项目依赖。请按照以下步骤安装它们:
访问Node.js官网,下载适合你操作系统的安装包。运行安装包并按照提示完成安装。npm会随Node.js一起安装。打开终端或命令提示符,输入以下命令来验证安装:
node -v
npm -v
2. 创建React应用
使用Create React App可以快速创建一个React应用。这是一个官方支持的脚手架工具,可以帮你快速启动和运行一个新的React项目。
-
安装Create React App:
npm install -g create-react-app -
创建一个新的React项目:
npx create-react-app my-app这里的
my-app是你项目的名字,你可以根据需要更改它。 -
进入项目目录:
cd my-app
3. 启动开发服务器
启动React应用的开发服务器,以便在本地预览你的应用。
npm start
这将启动开发服务器,并在默认的浏览器中打开你的应用(通常是http://localhost:3000)。
4. 开发和构建
现在你可以开始开发你的React应用了。所有的源代码都应该放在src目录下。使用npm start运行的应用会实时重新加载,当你保存文件时,浏览器会自动刷新以显示最新的更改。
实现待办事项列表
下面要开始实现待办事项列表:
App.js
import React, { useState } from 'react';
import './App.css';
function TodoApp() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const [editId, setEditId] = useState(null);
const [editInput, setEditInput] = useState('');
const [filter, setFilter] = useState('all'); // all, active, completed
const handleAddTodo = () => {
if (input !== '') {
const newTodo = {
id: Math.floor(Math.random() * 10000),
text: input,
completed: false,
};
setTodos([...todos, newTodo]);
setInput('');
}
};
const handleToggleTodo = (id) => {
setTodos(
todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
};
const handleDeleteTodo = (id) => {
setTodos(todos.filter((todo) => todo.id !== id));
};
const handleEditTodo = (id) => {
setEditId(id);
const todo = todos.find((todo) => todo.id === id);
setEditInput(todo.text);
};
const handleSaveEdit = () => {
const updatedTodos = todos.map((todo) =>
todo.id === editId ? { ...todo, text: editInput } : todo
);
setTodos(updatedTodos);
setEditId(null);
};
const handleClearCompleted = () => {
setTodos(todos.filter((todo) => !todo.completed));
};
const getVisibleTodos = () => {
switch (filter) {
case 'active':
return todos.filter((todo) => !todo.completed);
case 'completed':
return todos.filter((todo) => todo.completed);
default:
return todos;
}
};
return (
<div className='App'>
<h1>待办事项列表</h1>
<div className='todo-input'>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="添加新的待办事项"
/>
<button onClick={handleAddTodo}>添加</button>
</div>
<div className="view-selector">
<button onClick={() => setFilter('all')}>全部</button>
<button onClick={() => setFilter('active')}>未完成</button>
<button onClick={() => setFilter('completed')}>已完成</button>
<button onClick={handleClearCompleted}>清除已完成</button>
</div>
<ul className="todo-list">
{getVisibleTodos().map((todo) => (
<li key={todo.id} style={{ backgroundColor: todo.completed ? '#c1c1c1' : '#f1f1f1' }}>
<button onClick={() => handleToggleTodo(todo.id)}>
{todo.completed ? '√' : 'O'}
</button>
{editId === todo.id ? (
<input
type="text"
value={editInput}
onChange={(e) => setEditInput(e.target.value)}
onBlur={handleSaveEdit}
onKeyDown={(e) => {
if (e.key === 'Enter') handleSaveEdit();
}}
/>
) : (
<>
<span>{todo.text}</span>
<button onClick={() => handleEditTodo(todo.id)}>编辑</button>
</>
)}
<button onClick={() => handleDeleteTodo(todo.id)}>删除</button>
</li>
))}
</ul>
</div>
);
}
export default TodoApp;
App.css
.App {
text-align: center;
font-family: Arial, sans-serif;
margin-top: 50px;
}
.todo-input {
margin-bottom: 20px;
}
.todo-input input {
padding: 10px;
font-size: 16px;
width: 300px;
margin-right: 10px;
}
.todo-input button {
padding: 10px 15px;
font-size: 16px;
}
.view-selector {
background: #f1f1f1;
margin: 10px;
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.view-selector button {
background: #3bb7ff;
color: white;
border: none;
padding: 5px 10px;
cursor: pointer;
}
.view-selector button:hover {
background: #3b87ff;
}
.todo-list {
list-style-type: none;
padding: 0;
}
.todo-list li {
margin: 10px;
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.todo-list li button {
background: #3bb7ff;
color: white;
border: none;
padding: 5px 10px;
cursor: pointer;
}
.todo-list li button:hover {
background: #3b87ff;
}
.todo-list li input {
padding: 5px;
font-size: 16px;
width: 200px;
}
代码解析
- 使用useState钩子定义组件的状态:
todos:存储待办事项的数组。input:存储输入框中的文本。editId:存储当前正在编辑的待办事项的ID。editInput:存储正在编辑的待办事项的新文本。filter:存储当前的过滤状态(全部、未完成、已完成)。
- 功能
handleAddTodo函数:添加新的待办事项。handleToggleTodo函数:切换待办事项的完成状态。handleDeleteTodo函数:删除待办事项。handleEditTodo函数:开始编辑待办事项。handleSaveEdit函数:保存编辑后的待办事项。handleClearCompleted函数:清除所有已完成的待办事项。getVisibleTodos函数:根据过滤状态返回可见的待办事项数组。
- 视图
- 包含标题、输入框、添加按钮、视图选择器(全部、未完成、已完成、清除已完成)、待办事项列表。
- 待办事项列表中,每个待办事项显示完成状态(√或O)、文本、编辑和删除按钮。
- 如果待办事项正在编辑中,则显示输入框以允许编辑文本。