知识点:
- 拆分组件、实现静态组件,注意className、style的写法,className = "XXX" style={{style={{fontSize:'50px'}}
- 动态化初始列表,如何确定将数据放在哪个组件的state中 1、某个组件使用:放在自身的state里面 2、某些组件使用,放在公共的父组件state里面
- 关于父子之间通信 1、【父组件】给【子组件】:通过props传递 2、【子组件】给【父组件】通过props传递,要求父先给子一个函数
- 状态在哪里,操作状态的方法就在哪里
App.jsx
import React, { Component } from "react";
import Footer from "./components/Footer";
import Header from "./components/Header";
import List from "./components/List";
export default class App extends Component {
// 初始化状态
state = {
todos: [
{ id: "001", name: "吃饭", done: false },
{ id: "002", name: "睡觉", done: true },
{ id: "003", name: "敲代码", done: true },
],
};
// 添加Todo数值
addTodo = (todoObj) => {
const { todos } = this.state;
const newTodos = [todoObj, ...todos];
this.setState({ todos: newTodos });
};
// 勾选单选框 取消和选中
updateTodo = (id, done) => {
const { todos } = this.state;
const newTodos = todos.map((todoObj) => {
if (todoObj.id === id) return { ...todoObj, done };
else return todoObj;
});
this.setState({ todos: newTodos });
};
// 删除
deleteTodo = (id) => {
const { todos } = this.state;
const newTodos = todos.filter((todoObj) => {
return todoObj.id !== id;
});
this.setState({ todos: newTodos });
};
// 全选
checkAllTodo = (done) => {
const {todos} = this.state
const newTodos = todos.map((todoObj) => {
return {...todoObj,done}
});
this.setState({todos:newTodos})
}
deleteAllTodo = () => {
const { todos } = this.state;
const newTodos = todos.filter((todoObj) => {
return todoObj.done === false
});
this.setState({ todos: newTodos });
}
render() {
const { todos } = this.state;
return (
<div>
<Header addTodo={this.addTodo} />
<List
todos={todos}
updateTodo={this.updateTodo}
deleteTodo={this.deleteTodo}
/>
<Footer todos={todos} deleteAllTodo={this.deleteAllTodo} checkAllTodo={this.checkAllTodo}/>
</div>
);
}
}
Footer.jsx
import React, { Component } from "react";
import "./index.css";
export default class index extends Component {
handleCheckAll = (e) => {
this.props.checkAllTodo(e.target.checked);
};
handleDelAll = () => {
this.props.deleteAllTodo()
}
render() {
const { todos } = this.props;
// 已完成个数
// 方法1
// const doneCount = todos.filter((todoObj)=>{
// return todoObj.done == true
// })
// 方法2
const doneCount = todos.reduce((pre, todos) => {
return pre + (todos.done ? 1 : 0);
}, 0);
// 总数
const total = todos.length;
return (
<div className="todo-footer">
<label>
{/*注意不能使用defaultChecked,这个只能在初始化的时候执行一次,并且如果使用checkede就必须添加onChange*/}
<input
type="checkbox"
onChange={this.handleCheckAll}
checked={doneCount === total && total !== 0 ? true : false}
/>
</label>
<span>
<span>已完成{doneCount}</span> / 全部{total}
</span>
<button onClick={this.handleDelAll} className="btn btn-danger">清除已完成任务</button>
</div>
);
}
}
Header.jsx
import React, { Component } from "react";
import { nanoid } from "nanoid";
import PropTypes from "prop-types";
import "./index.css";
export default class index extends Component {
// 对接收的参数进行限制
static propTypes = {
addTodo: PropTypes.func.isRequired,
};
handleKeyUp = (e) => {
const { target } = e;
if (e.keyCode !== 13) return;
if (target.value.trim() === "") {
alert("输入为空");
return;
}
const todoObj = { id: nanoid(), name: target.value, done: false };
this.props.addTodo(todoObj);
target.value = "";
};
render() {
return (
<div className="todo-header">
<input
onKeyUp={this.handleKeyUp}
type="text"
placeholder="按住回车确定"
/>
</div>
);
}
}
Item.jsx
import React, { Component } from "react";
import "./index.css";
import PropTypes from "prop-types";
export default class index extends Component {
static propTypes = {
updateTodo: PropTypes.func.isRequired,
deleteTodo: PropTypes.func.isRequired,
};
// 初始化状态
state = { mouse: false };
// 移入和移出样式改变
handleMouse = (flag) => {
return () => {
this.setState({ mouse: flag });
};
};
// 勾选单选框 取消和选中
handleCheck = (id, done) => {
return (e) => {
const { target } = e;
this.props.updateTodo(id, target.checked);
};
};
// 删除
handleDelete = (id, name) => {
return () => {
if (window.confirm(`您确认要删除 ${name} 吗?`)) {
this.props.deleteTodo(id);
}
else{
console.log('用户点击了取消');
}
};
};
render() {
const { id, name, done } = this.props;
const { mouse } = this.state;
return (
<div>
<li
style={{ background: mouse ? "#ddd" : "white" }}
onMouseEnter={this.handleMouse(true)}
onMouseLeave={this.handleMouse(false)}
>
<label>
<input
type="checkbox"
checked={done}
onChange={this.handleCheck(id, done)}
/>
<span>{name}</span>
</label>
<button
onClick={this.handleDelete(id, name)}
className="btn btn-danger"
style={{ display: mouse ? "block" : "none" }}
>
删除
</button>
</li>
</div>
);
}
}
List.jsx
import React, { Component } from "react";
import Item from "../Item";
import PropTypes from "prop-types";
import "./index.css";
export default class index extends Component {
static propTypes = {
updateTodo: PropTypes.func.isRequired,
deleteTodo: PropTypes.func.isRequired,
todos: PropTypes.array.isRequired,
};
render() {
const { todos, updateTodo,deleteTodo } = this.props;
return (
<ul className="todo-main">
{todos.map((n) => {
return <Item key={n.id} {...n} updateTodo={updateTodo} deleteTodo={deleteTodo}></Item>;
})}
</ul>
);
}
}
效果演示
注意:此处CSS样式没有上传
Gitee链接:React_Study_Ac: React-Study