React经典案例todoList记录
虽然是简单的案例,但值得学习,简单记录了下todoList的案例、代码结构如下,忽略css部分
**
话不多说,上代码
1、App.jsx代码:
import React, { Component } from 'react'
import Header from './compoents/Header/index'
import List from './compoents/List'
import Footer from './compoents/Footer'
import './App.css'
export default class App extends Component {
//状态在哪里,操作状态的方法就写在哪里
//初始化状态
state = {
todos:[
{id:'001',name:'吃饭',done:true},
{id:'002',name:'睡觉',done:true},
{id:'003',name:'写代码',done:false},
{id:'004',name:'逛街街',done:false},
]
}
//函数
//addTodo用于添加一个todo,接收的参数是todo对象
addTodo = (todoObj)=>{
console.log("App",todoObj)
//获取原todos
const {todos} = this.state
//在原来的todos上追加一个todo
const newTodos = [todoObj,...todos]
//更新状态
this.setState({todos:newTodos})
}
//更新item是否完成 用于更新一个todo对象
updateTodo=(id,done)=>{
//函数体
//获取状态中的todos
const {todos} = this.state
//判断勾选的item是哪一项去进行更新
//加工数据
const newTodos = todos.map((todoObj)=>{
//测试
// let obj = {a:1,b:2}
// let obj2 = {...obj,b:3}
// console.log(obj2)//打印结果:{a:1,b:3}
if(todoObj.id===id){
//返回新的对象
return {...todoObj,done:done}
}else{
//无匹配上 直接返回
return todoObj
}
})
this.setState({todos:newTodos})
}
//删除todo的回调函数
deleteTodo = (id)=>{
//函数体
//获取原来的todos
const {todos} = this.state
//删除指定id的todo对象
//从数组里面删除指定id的元素
const newTodos = todos.filter((todoObj)=>{
return todoObj.id !==id
})
//更新状态
this.setState({todos:newTodos})
}
//全选
checkAllTodo=(done)=>{
//获取原来的todos
const {todos} = this.state
//加工数据
const newTodos = todos.map((todoObj)=>{
return {...todoObj,done:done}
})
//更新状态
this.setState({todos:newTodos})
}
//清除所有已完成
clearAllDone = ()=>{
//获取原来的todos
const {todos} = this.state
//加工数据
const newTodos = todos.filter((todoObj)=>{
return todoObj.done ===false
})
//更新状态
this.setState({todos:newTodos})
}
render() {
const {todos} = this.state
return (
<div className='todo-container'>
<div className='todo-wrap'>
<Header addTodo={this.addTodo}/>
<List todos = {todos} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo}/>
<Footer todos = {todos} checkAllTodo={this.checkAllTodo} clearAllDone={this.clearAllDone}/>
</div>
</div>
)
}
}
2、Header.jsx代码:
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import {nanoid} from 'nanoid'
import './index.css'
console.log(nanoid())
export default class Header extends Component {
//对接收的props进行:类型、必要性的限制
static propTypes = {
addTodo:PropTypes.func.isRequired
}
//键盘回车事件
handleKeyUp = (event)=>{
//函数体
//event.keyCode原生获取键盘键下对应key值
// const {keyCode,target} = event
// if(keyCode!==13) return
// console.log(target.value)
//keyCode已废除使用 直接使用key
//解构赋值key,target
const {key,target} = event
//判断是否是回车案件
if(key!=='Enter') return
console.log(target.value,key);
//子组件给父组件传值,要求父给子通过props传的是一个函数
//子通过调用父的函数达到给父传值的目的
//准备好一个todo对象
//判断:添加的name不能为空
if(target.value.trim()===''){
alert("输入不能为空")
return
}
const todoObj = {id:nanoid(),name:target.value,done:false}
//将todoObj传递给父组件
this.props.addTodo(todoObj)
//nanoid()生成唯一字符串保证标志唯一
//清空输入
target.value = ""
}
render() {
return (
<div className='to-header'>
<input onKeyUp={this.handleKeyUp} type="text" placeholder='请输入你的任务名称,按回车键确认'/>
</div>
)
}
}
3、List.jsx代码:
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Item from '../Item'
import './index.css'
export default class List extends Component {
//对接收的props进行:类型、必要性的限制
static propTypes = {
todos:PropTypes.array.isRequired,
updateTodo:PropTypes.func.isRequired,
deleteTodo:PropTypes.func.isRequired,
}
render() {
const {todos,updateTodo,deleteTodo} = this.props
console.log('列表数据',todos)
return (
<ul className='todo-main'>
{
todos.map((todo,index)=>{
//拆分传递
// return <Item key={todo.id} id={todo.id} name={todo.name} done={todo.done}/>
//批量传递...
return <Item key={todo.id} {...todo} updateTodo={updateTodo} deleteTodo={deleteTodo}/>
})
}
</ul>
)
}
}
4、Item.jsx代码:
import React, { Component } from 'react'
import './index.css'
export default class Item extends Component {
//维护一个状态值,用于标识鼠标是否移入状态
state = {mouse:false}
//鼠标移入移出回调
handMouse=(flag)=>{
return ()=>{
//根据鼠标移入移出与否更新state状态
this.setState({mouse:flag})
//console.log(this.state.mouse)
}
}
//复选框是否勾选事件接收参数id
handCheck=(id)=>{
//函数体
return(event)=>{
//event.target.checked获取复选框是否勾选状态
console.log(id,event.target.checked)
this.props.updateTodo(id,event.target.checked)
}
}
//删除todo的回调
handDelete=(id)=>{
//函数体
console.log("删除的todo的id",id)
if(window.confirm("确认删除吗?")){
this.props.deleteTodo(id)
}
}
render() {
const {id,name,done} = this.props
const {mouse} = this.state
return (
<li style={{backgroundColor:mouse?'#ddd':'white'}} onMouseEnter={this.handMouse(true)} onMouseLeave={this.handMouse(false)}>
<label>
<input type="checkbox" checked={done} onChange={this.handCheck(id)}/>
<span>{name}</span>
</label>
<button onClick={()=>{this.handDelete(id)}} className='btn btn-danger' style={{display:mouse?'block':'none'}}>删除</button>
</li>
)
}
}
5、Footer.jsx代码:
import React, { Component } from 'react'
import './index.css'
export default class Footer extends Component {
//全选框change函数
handleCheckAll=(event)=>{
//函数体
this.props.checkAllTodo(event.target.checked)
}
//清除已完成的回调函数
handleClearAllDone = ()=>{
this.props.clearAllDone()
}
render() {
const {todos} = this.props
//计算已完成的个数使用数组的reduce方法
const doneCount = todos.reduce((pre,todo)=>{return pre+(todo.done?1:0)},0)
console.log(doneCount,'已完成')
//总数
const total = todos.length
return (
<div className='todo-footer'>
<label><input type="checkbox" onChange={this.handleCheckAll} checked={doneCount===total&&total!==0?true:false}/>
</label><span>已完成{doneCount}</span>/全部{total}
<button onClick={this.handleClearAllDone} className='btn btn-danger'>清除已完成任务</button>
</div>
)
}
}
效果如下:新增、单个删除、删除已完成、完成勾选、取消勾选、全选、全部取消勾选、计数**
兄弟萌赶快试试吧
代码如下: