React todoList 案例

 

整体流程思路 

  1. 组件拆分:header list>item  footer   
  2. 布局出静态代码
  3. 书写事件处理函数(数据在哪里、具体就在哪里修改)、这里数据全部放在 最外层APP组件、内部子组件触发回调(传入参数) 实际调用 app组件的处理函数(使用props 把函数传入进去)
  4. 具体操作为 添加数据、修改数据状态、删除数据、全选反选状态、清除已选状态
  5. 还可以继续优化、如数据存放在浏览器本地存储当中...

App.jsx 数据和方法都定义在这里 向子组件传递

import React, { Component } from 'react'
import {nanoid} from 'nanoid'
import Header from './component/Header';
import List from './component/List';
import Footer from './component/Footer';
import './App.css';


export default class App extends Component {
  state = {
    todoData:[
      {id:'001',done:true,context:'吃饭'},
      {id:'002',done:true,context:'睡觉'},
      {id:'003',done:false,context:'敲代码'}
    ]
  }

  addTodoData = (context) =>{
      const newObj = {id:nanoid(),context:context,done:false}
      this.setState({
        todoData:[newObj,...this.state.todoData]
      }) 
  }


  editSele = (done,id) =>{
    const newA = this.state.todoData.map(item =>{
      if(item.id === id) {
        return {...item,done}
      }else return item
    })
    this.setState({
      todoData:newA
    })
  }

  clearItem = (id) =>{
    if(window.confirm('确定要删除吗?')){
    const upData = this.state.todoData.filter(x =>{
      return x.id !== id
    })
          this.setState({
      todoData:upData
    })
    }else return
  }


  changeAllSele = (done) =>{
        const newA = this.state.todoData.map(item =>{
        return {...item,done}
    })
    this.setState({
      todoData:newA
    })
  }

  layoffDone = () =>{
    const load = this.state.todoData.filter(x =>{
      return x.done === false
    })

      this.setState({
      todoData:load
    })
  }

  render(){
      return (
    <div className="todo-container">
    <div className="todo-wrap">
      <Header addTodoData={this.addTodoData}></Header>
      <List todoData={this.state.todoData} editSele={this.editSele} clearItem={this.clearItem}></List>
      <Footer todoData={this.state.todoData}  changeAllSele={this.changeAllSele}  layoffDone={this.layoffDone}></Footer>
    </div>
  </div>
  );
  }

}

 Header.jsx 有添加功能 传入输入框的数值 触发传进来的函数

import React, { Component } from 'react'
import './index.css'
import PropTypes from 'prop-types'

export default class Header extends Component {

	static propTypes = {
		addTodoData:PropTypes.func.isRequired
	}
  handleKeyUp = (e) =>{
      if(e.keyCode !==13) return
      if(e.target.value.trim() === ''){
        alert('输入内容不能为空')
        return
      }
      const context = e.target.value.trim()
      this.props.addTodoData(context)
      e.target.value=''
    }
  render() {
    return (
      <div className="todo-header">
        <input type="text"  onKeyUp={this.handleKeyUp} placeholder="请输入你的任务名称,按回车键确认"/>
      </div>
    )
  }
}

List.jsx 整体列表 再 map return 每一项

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Item from './Item'

export default class List extends Component {

	static propTypes = {
		todoData:PropTypes.array.isRequired,
    editSele:PropTypes.func.isRequired,
    clearItem:PropTypes.func.isRequired
	}

  render() {
    return (
        <ul className="todo-main">
          {
            this.props.todoData.map(todo =>{
              return <Item key={todo.id} {...todo}  editSele={this.props.editSele} clearItem={this.props.clearItem}></Item>
            })
          }
      </ul>
    )
  }
}

Item.jsx 每一项列表  有修改状态 和 删除当前项 传入ID 触发传进来的函数

还给每个li  都添加了 鼠标移入事件 通过布尔值和 三元表达式 修改显示状态

 

import React, { Component } from 'react'
import './index.css'

export default class Item extends Component {
  state = {
    mouse:false
  }
  throughItem = (flag) =>{
    return () =>{
        this.setState({mouse:flag})
    }
  }

  changeSele = (id) =>{
    return (e) =>{
      this.props.editSele(e.target.checked,id)
    }
  }

  killItem = (id) =>{
    return () =>{
      this.props.clearItem(id)
    }
  }

  render() {
    const{id,done,context} = this.props
    const {mouse} = this.state
    return (
          <li onMouseEnter={this.throughItem(true)} onMouseLeave={this.throughItem(false)} style={mouse ? {background:'#f0f0f0'} : {background:'#fff'}}>
          <label>
            <input type="checkbox" checked={done} onChange={this.changeSele(id)}/>
            <span>{context}</span>
          </label>
          <button className="btn btn-danger" style={mouse ? {display:'block'} : {display:'none'}} onClick={this.killItem(id)}>删除</button>
        </li>
    )
  }
}

footer.jsx 底部组件 reduce方法计算出数据中已选的项、把点击全选后的状态传递出去 删除已选的项不用传参 直接调用父组件函数

import React, { Component } from 'react'
import './index.css'

export default class Footer extends Component {

changeAllSele1 = (e) =>{
    this.props.changeAllSele(e.target.checked)
}

layoff = () =>{
  this.props.layoffDone()
}

  render() {
    const {todoData} = this.props
    let total = todoData.length
    let sele = todoData.reduce((a,b) =>a + (b.done?1:0),0)
    return (
      <div className="todo-footer">
        <label>
          <input type="checkbox" onChange={this.changeAllSele1}  checked={total===sele&&total!==0?true:false}  />
        </label>
        <span>
          <span>已完成{sele}</span> / 全部{total}
        </span>
        <button className="btn btn-danger" onClick={this.layoff}>清除已完成任务</button>
      </div>
    )
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值