React实现TodoList

React实现一个TodoList案例,大部分教学视频里面好像都会教,笔者会点JavaScript,略微学了点Vue,写起React来到也轻松,看点React对Vue的组件化到也是一种新的理解方式。

具体预览

话不多说,环境搭建。

npx create-react-app todolist

此步操作会新建一个todolist文件夹,使用Vscode打开此文件夹,安装所需依赖

# 通用的样式库
npm install bootstrap
# 整合库
npm install reactstrap

首先删除src下所有文件,然后根据此文内容在src下一个一个新建文件即可。

新建index.js

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "bootstrap/dist/css/bootstrap.min.css";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

新建App.js

import "./App.css";
import React from "react";
import InputTodo from "./InputTodo";
import TodoList from "./TodoList";
import EndFoot from "./EndFoot";

const lsKey = "todoList";
const setlocalState = (state) => {
  localStorage.setItem(lsKey, JSON.stringify(state));
};
const getlocalState = () => {
  const str = localStorage.getItem(lsKey);
  if (str) {
    return JSON.parse(str);
  } else {
    return [];
  }
};

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // 任务列表
      todoList: getlocalState(),
    };
  }
  // 添加任务
  addTodoList = (item) => {
    const todoList = this.state.todoList.slice();
    todoList.unshift(item);
    this.setState({ todoList: todoList });
    setlocalState(this.state.todoList);
  };
  // 删除任务
  removeTodoList = (index) => {
    if (window.confirm("确认删除任务?")) {
      const todoList = this.state.todoList.slice();
      todoList.splice(index, 1);
      this.setState({ todoList: todoList });
      setlocalState(this.state.todoList);
    }
  };
  // 全选
  checkAll = () => {
    const todoList = this.state.todoList.slice();
    todoList.forEach((item) => {
      item.check = true;
    });
    this.setState({ todoList: todoList });
    setlocalState(this.state.todoList);
  };
  // 全选
  checkNoAll = () => {
    const todoList = this.state.todoList.slice();
    todoList.forEach((item) => {
      item.check = false;
    });
    this.setState({ todoList: todoList });
    setlocalState(this.state.todoList);
  };
  // 移入移出事件
  mouseOverOut = (index, type) => {
    const todoList = this.state.todoList.slice();
    const item = todoList[index];
    item.showDel = type;
    todoList.splice(index, 1, item);
    this.setState({ todoList: todoList });
    setlocalState(this.state.todoList);
  };

  // 点击选中事件
  clickItem = (index) => {
    const todoList = this.state.todoList.slice();
    const item = todoList[index];
    item.check = !item.check;
    todoList.splice(index, 1, item);
    this.setState({ todoList: todoList });
    setlocalState(this.state.todoList);
  };

  // 清除已勾选的任务
  clearCheckItem = () => {
    const todoList = this.state.todoList.slice();
    this.setState({ todoList: todoList.filter((i) => !i.check) });
    setlocalState(this.state.todoList);
  };
  render() {
    return (
      <div className="App">
        <div className="content">
          <InputTodo addTodoList={this.addTodoList} />
          <TodoList
            todoList={this.state.todoList}
            mouseOverOut={this.mouseOverOut}
            clickItem={this.clickItem}
            removeTodoList={this.removeTodoList}
          />
          <EndFoot
            todoList={this.state.todoList}
            clearCheckItem={this.clearCheckItem}
            checkAll={this.checkAll}
            checkNoAll={this.checkNoAll}
          />
        </div>
      </div>
    );
  }
}
export default App;

新建App.css

.App {
  display: flex;
  justify-content: center;
  align-items: center;
}

.App .content {
  border: 1px solid #ccc;
  padding: 5px;
  width: 400px;
}
.App .list {
  padding-top: 5px;
  padding-bottom: 5px;
}

.App .list .item {
  display: flex;
  height: 30px;
  justify-content: space-between;
  align-items: center;
}

.App .end {
  height: 47px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border: solid #b6c3d0 1px;
  border-radius: 5px;
}

新建InputTodo.js

import { Input } from "reactstrap";
import React from "react";

class InputTodo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      inputText: "",
    };
  }
  render() {
    return (
      <div>
        <Input
          value={this.state.inputText}
          onChange={(e) => this.setState({ inputText: e.target.value })}
          placeholder="请输入任务名称, 按回车键确认"
          onKeyDown={(event) => {
            if (event.key === "Enter") {
              if (!this.state.inputText) {
                alert("不可添加空任务");
                return;
              }
              this.props.addTodoList({
                showDel: false,
                check: false,
                label: this.state.inputText,
              });
              this.setState({ inputText: "" });
            }
          }}
        />
      </div>
    );
  }
}
export default InputTodo;

新建TodoList.js

import { Input, ListGroupItem, ListGroup, Button } from "reactstrap";
import React from "react";
class TodoList extends React.Component {
  renderList() {
    return this.props.todoList.map((i, index) => {
      return (
        <ListGroupItem
          key={index}
          action
          href="#"
          tag="a"
          onClick={() => this.props.clickItem(index)}
          onMouseOver={() => this.props.mouseOverOut(index, true)}
          onMouseOut={() => this.props.mouseOverOut(index, false)}
        >
          <div className="item">
            <div>
              <Input
                type="checkbox"
                id="checkItem"
                checked={i.check}
                onChange={(e) => {}}
              />
              <span style={{ paddingLeft: "10px" }}>{i.label}</span>
            </div>
            <div>
              {i.showDel ? (
                <Button
                  color="danger"
                  size="sm"
                  onClick={(e) => {
                    e.stopPropagation();
                    this.props.removeTodoList(index);
                  }}
                >
                  删除
                </Button>
              ) : (
                <div></div>
              )}
            </div>
          </div>
        </ListGroupItem>
      );
    });
  }

  render() {
    return (
      <div className="list">
        <ListGroup>{this.renderList()}</ListGroup>
      </div>
    );
  }
}
export default TodoList;

新建EndFoot.js

import { Input, Button } from "reactstrap";
import React from "react";

class EndFoot extends React.Component {
  render() {
    return (
      <div className="end">
        <div style={{ paddingLeft: "17px" }}>
          <Input
            type="checkbox"
            checked={
              this.props.todoList.filter((i) => i.check).length ===
              this.props.todoList.length
            }
            onChange={(e) => {
              if (e.target.checked) {
                this.props.checkAll();
              } else {
                this.props.checkNoAll();
              }
            }}
          />
          <span style={{ paddingLeft: "10px" }}>
            已完成{this.props.todoList.filter((i) => i.check).length}/全部
            {this.props.todoList.length}
          </span>
        </div>

        <div>
          {this.props.todoList.filter((i) => i.check).length > 0 ? (
            <Button
              color="danger"
              size="sm"
              onClick={this.props.clearCheckItem}
            >
              清除已完成任务
            </Button>
          ) : (
            <div></div>
          )}
        </div>
      </div>
    );
  }
}
export default EndFoot;

最后运行项目

npm start

即可查看效果,代码不多,展示了最经典的React写法,很适合用来了解学习React。

封面

原神 八重神子 4k 电脑 壁纸_彼岸图网


React实现TodoList
https://wangijun.com/2023/03/08/react-02/
作者
无良芳
发布于
2023年3月8日
许可协议