使用React 实现一个简单的待办事项列表 | 豆包MarsCode AI刷题

72 阅读4分钟

使用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项目。

  1. 安装Create React App

    npm install -g create-react-app
    
  2. 创建一个新的React项目

    npx create-react-app my-app
    

    这里的my-app是你项目的名字,你可以根据需要更改它。

  3. 进入项目目录

    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)、文本、编辑和删除按钮。
    • 如果待办事项正在编辑中,则显示输入框以允许编辑文本。

实现效果

image.png