React尚硅谷todoList案例

一、根据静态页面将代码进行拆分

把初始的静态界面拆分为四个组件,分别为Header、List、Item、Footer,注意拆分时修改代码的格式,如class="btn btn-danger"改为className=“btn btn-danger”在这里插入图片描述

二、传递初始State
1、创建初始数据并传递给List

在APP.jsx中加入初始的数据,因为这些数据需要List通过Item进行最开始的展示,所以将数据传递给List。

state = {todos:[
		{id:'001',name:'eat',done:true},
		{id:'002',name:'sleep',done:true},
		{id:'003',name:'work',done:false}
	]}
	render() {
		const {todos} = this.state
		return (
			<div className="todo-container">
				<div className="todo-wrap">
					<Header/>
					<List todos={todos}/>
					<Footer/>
				</div>
			</div>
		)
	}
2、List与Item接收初始数据

List接收数据后通过map方法循环todos中的数据形成Item组件,在map中key值取todos最开始定义的id即可,同时将todos内的数据传递给Item。

		const {todos} = this.props
		return (
			<ul className="todo-main">
				{
					todos.map( todo =>{
						return <Item key={todo.id} {...todo}/>
					})
				}
			</ul>
        )

Item同理,接收数据后放入Li标签内(id目前暂未用到,所以先去掉),这里可以使用defaultChecked方法来通过初始的done来确定是否勾选前面的checkbox,但使用defaultChecked会有一些问题,后面再改掉。

		const {name,done} = this.props
        return (
        <li>
          <label>
            <input type="checkbox" defaultChecked={done}/>
            <span>{name}</span>
          </label>
          <button className="btn btn-danger" style={{'display':'none'}}>删除</button>
        </li>
        )

效果如下:在这里插入图片描述

三、Header添加待办事项
1、确定回车的keyCode

通过onKeyUp(onkeyup 事件会在键盘按键被松开时发生)来输出一下按键的keyCode,确定回车的keyCode。

	handleKeyUp =(event)=>{
        console.log(event.target.value,event.keyCode);//控制台观察回车的keyCode为13
   	 	}
    render() {
        return (
            <div className="todo-header">
                <input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认" />
            </div>
        )
    }
2、Header组件修改App的state

因为Header是App的子组件,所以如果想要修改父组件的数据,可以在App中向Header传递一个函数,在Header中使用这个函数修改App的state,就完成了子组件向父组件传递数据的过程。
App.jsx

	addTodos = (todoObj) => {
		const { todos } = this.state
		const newTodos = [todoObj,...todos]
		this.setState({todos:newTodos})
		}
		...
		...
		...
	//向Header中传递函数
	<Header addTodos={this.addTodos} />
	    ···

Header.jsx

	handleKeyUp = (event) => {
        const { keyCode, target } = event //解构赋值
        if (keyCode !== 13) return //判断是否为回车
        if (target.value.trim() === '') { //校验输入不可以为空值
            alert('输入不能为空!')
            return
        }
        const todoObj = { id: nanoid(), name: target.value, done: false } //id通过nanoid来设置,也可以用random设置
        this.props.addTodos(todoObj)
        target.value = '' //添加结束后把输入栏置为空
   		}
   		...
   		...
   		...
	//向Header中传递函数
	  <input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认" />
	    ···
四、鼠标移入移出效果

使用onMouseEnter与onMouseLeave完成添加鼠标移入与移出效果:在Item中添加mouse的状态,通过函数设置该状态为true或者false来控制鼠标移入移出时Li的背景色变化,同时删除按钮也根据mouse的状态来进行展示或者隐藏。

  state = { mouse: false }
  handleMouse = (flag) => {
    return () => { //需要返回函数,否则下面会一直调用handleMouse
      this.setState({ mouse: flag })
    	}
  	}
  	···
  	···
  	···
   <li style={{ backgroundColor: mouse ? '#ddd' : 'white' }} onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)}> 
   	···
   <button onClick={()=> this.handleDelete(id) } className="btn btn-danger" style={{display:mouse?'block':'none'}}>删除</button>
  	···
五、勾选事件与取消勾选事件、添加props限制
1、勾选事件与取消勾选事件

checkbox在Item当中,所以如果想要通过勾选来改变事件的done值的话,需要在checkbox当中添加onChange方法。因为Item相当于App的“孙子组件”,所以这里想要修改事件的done值的话,还是需要在App当中加入更新todos的函数来进行修改,然后传递给List,List再传递给Item,过程类似于增加一个todo。
App.jsx

updateTodos = (id,done)=>{
		const{todos} = this.state
		const newTodos = todos.map((todoObj)=>{
			if(todoObj.id === id) return {...todoObj,done:done}
			else return todoObj//根据id来修改done的状态,上面done:done可以简写为done
		})
		this.setState({todos:newTodos})
	}

List.jsx

const {todos,updateTodos} = this.props
		return (
			<ul className="todo-main">
				{
					todos.map( todo =>{
						return <Item key={todo.id} {...todo} updateTodos={updateTodos}/>
					})
				}
			</ul>
        )

Item.jsx

handleCheck = (id) => {
    return (event) => {
      this.props.updateTodos(id,event.target.checked) //传回id与勾选框的状态
    }
  }
  ···
  ···
  ···
  <input type="checkbox" defaultChecked={done} onChange={this.handleCheck(id)} /> //传入id,根据id来修改App中state的对应值
  ···
2、限制props

添加对props的限制,没装的话需要先安装一下。例子如下:

import PropTypes from 'prop-types'
···
static propTypes = {
		todos:PropTypes.array.isRequired,
		updateTodo:PropTypes.func.isRequired,
		deleteTodo:PropTypes.func.isRequired,
	}
六、删除todo

与添加todo类似,同样是在App中完成deleteTodos函数,传递到Item中使用,注意删除前使用confirm来确定是否删除。
App.jsx

deleteTodos = (id)=>{
		const{todos}=this.state
		const newTodos = todos.filter((todoObj)=>{
			return todoObj.id!==id
		})
		this.setState({todos:newTodos})
	}

Item.jsx

 handleDelete = (id) => {
      if (window.confirm('确定删除吗')) {
          this.props.deleteTodos(id)
      }
  }
  ···
<button onClick={() => this.handleDelete(id)} className="btn btn-danger" style={{ 'display': mouse ? 'block' : 'none' }}>删除</button>

七、全选与删除已完成事件
1、全选

先要完成Footer中 已完成/全部 的功能,这里全部的数值直接取todos的长度,已完成的数值通过reduce方法来判断已完成事件的数量。

const doneCount = todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0),0)
const total = todos.length

在这里插入图片描述
reduce函数

arr.reduce(function(prev,cur,index,arr){
...
}, init);
参数
prev 必需。累计器累计回调的返回值; 表示上一次调用回调时的返回值,或者初始值 init;
cur 必需。表示当前正在处理的数组元素;
index 可选。表示当前正在处理的数组元素的索引,若提供 init 值,则起始索引为- 0,否则起始索引为1;
arr 可选。表示原数组;
init 可选。表示初始值。
原文链接:https://blog.csdn.net/qq_38970408/article/details/121018660

因为defaultChecked只在第一次起作用,所以完成 已完成/全部的展示功能后,给Footer对应的checkbox添加onChange方法,同时添加checked方法(checked必须有onChange方法)。同时将前面Item中checkbox的也改为checked用法。

checkAll函数

这个函数包括全选以及全不选。Footer中的checkAll方法要传入checkbox的check状态,这样在App中就可以根据这个状态来调整Item中全部checkbox的完成状态。
当Item中的checkbox全部勾选时,也要改变Footer中checkbox的状态,这个通过checked方法实现就可以。
Footer.jsx

checkAll = (event)=>{
        this.props.checkAll(event.target.checked)
    }
    ···
    ···
    ···
<input type="checkbox" onChange={this.checkAll} checked={doneCount === total && total !== 0 ? true : false} />

App.jsx

const {todos} = this.state
const newTodos = todos.map((todoObj)=>{
			return {...todoObj,done}
		})
this.setState({todos:newTodos})
2、清除完成事件

跟删除类似,Footer的button使用App传入的方法,在App的方法中返回done值为false的事件即可。
App.jsx

clearAll=()=>{
		const{todos} = this.state
		const newTodos = todos.filter((todoObj)=>{
			return !todoObj.done
		})
		this.setState({todos:newTodos})
	}

源代码来源:尚硅谷https://www.bilibili.com/video/BV1wy4y1D7JT

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值