React实现todolist

17 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述

将整个案列拆分成了4个组件

publick文件夹

index:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <link rel="stylesheet" href="./css/bootstrap.css"/>
    <title>react脚手架</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

src 文件夹

app.jsx

import React, { Component } from 'react'
import Header from './components/Header'
import Footer from './components/Footer'
import List from './components/List'
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},
    ]}
    //addTodo用于添加一个todo,接受的参数是todo对象
    addTodo = (todoObj) =>{
        //获取原todos
        const {todos} = this.state
        //追加一个todo
        const newTodos = [todoObj,...todos]
        //更新状态
        this.setState({todos:newTodos})
    }

    //updatetodo用于更新一个todo对象
    updateTodo = (id,done) =>{
        //获取状态中的todos
        const {todos} = this.state
        //匹配处理数据
        const newTodos = todos.map((todoObj)=>{
            if(todoObj.id === id)return {...todoObj,done}
            else return todoObj
        })
        this.setState({todos:newTodos})
    }

    //用于删除todo对象
    deleteTodo = (id) =>{
        //获取原来的todos
        const{todos} = this.state
        const newTodos = todos.filter((todoObj)=>{
            return todoObj.id!== id
        })
        this.setState({todos:newTodos})
    }

    //checkAllTodo用于全选
    checkAllTodo = (done)=>{
        //获取原来的todos
        const {todos} = this.state
        //加工数据
        const newTodos = todos.map((todoObj)=>{
            return {...todoObj,done}
        })
        //更新状态
        this.setState({todos:newTodos})
    }
    //用于清除所有已完成的事件
       clearAllDone=()=>{
         //获取原来todos
         const {todos} = this.state
         //过滤数据
         const neewTodos = todos.filter((todoObj)=>{
           return !todoObj.done
         })
         //更新状态
         this.setState({todos:neewTodos})
       }
           render() {
        const {todos} = this.state
        return (
            <div>
                <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>
            </div>
        )
    }
}

app.css

/*base*/
body {
    background: #fff;
  }
  
  .btn {
    display: inline-block;
    padding: 4px 12px;
    margin-bottom: 0;
    font-size: 14px;
    line-height: 20px;
    text-align: center;
    vertical-align: middle;
    cursor: pointer;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
    border-radius: 4px;
  }
  
  .btn-danger {
    color: #fff;
    background-color: #da4f49;
    border: 1px solid #bd362f;
  }
  
  .btn-danger:hover {
    color: #fff;
    background-color: #bd362f;
  }
  
  .btn:focus {
    outline: none;
  }
  
  .todo-container {
    width: 600px;
    margin: 0 auto;
  }
  .todo-container .todo-wrap {
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
  }
  
  /*header*/
  .todo-header input {
    width: 560px;
    height: 28px;
    font-size: 14px;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 4px 7px;
  }
  
  .todo-header input:focus {
    outline: none;
    border-color: rgba(82, 168, 236, 0.8);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
  }
  
  /*main*/
  .todo-main {
    margin-left: 0px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding: 0px;
  }
  
  .todo-empty {
    height: 40px;
    line-height: 40px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding-left: 5px;
    margin-top: 10px;
  }
  /*item*/
  li {
    list-style: none;
    height: 36px;
    line-height: 36px;
    padding: 0 5px;
    border-bottom: 1px solid #ddd;
  }
  
  li label {
    float: left;
    cursor: pointer;
  }
  
  li label li input {
    vertical-align: middle;
    margin-right: 6px;
    position: relative;
    top: -1px;
  }
  
  li button {
    float: right;
    display: none;
    margin-top: 3px;
  }
  
  li:before {
    content: initial;
  }
  
  li:last-child {
    border-bottom: none;
  }
  
  /*footer*/
  .todo-footer {
    height: 40px;
    line-height: 40px;
    padding-left: 6px;
    margin-top: 5px;
  }
  
  .todo-footer label {
    display: inline-block;
    margin-right: 20px;
    cursor: pointer;
  }
  
  .todo-footer label input {
    position: relative;
    top: -1px;
    vertical-align: middle;
    margin-right: 5px;
  }
  
  .todo-footer button {
    float: right;
    margin-top: 5px;
  }
  

comment-组件部分

在这里插入图片描述

头部组件Header

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

export default class Header extends Component {

    //对接受的props进行类型,以及必要性的限制
    // static PropTypes ={
        // addTodo:PropTypes.func.isRequired
    // }


    handleKeyUp = (event)=>{
        if(event.keyCode!== 13) return
        //添加的todo不能为空
        if(event.target.value.trim() === ''){
            alert('输入不能为空')
            return
        }
        //准备好一个todo对象
        const todoObj = {id:nanoid(),name:event.target.value,done:false}
        //将todoobj传递给APP
        this.props.addTodo(todoObj)
        //清空输入
        event.target.value = ''
    }
    render() {
        return (
             <div className="todo-header">
                <input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认"/>
             </div>
        )
    }
}

List组件

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

export default class List extends Component {

    // static PropTypes ={
        // todos:PropTypes.arr.isRequired,
        // updateTodo:PropTypes.func.isRequired
    // }
    render() {
        const {todos,updateTodo,deleteTodo} = this.props
        return (
            <ul className="todo-main">
                {
                    todos.map( todo =>{
                        return <Item key={todo.id} {...todo} updateTodo = {updateTodo} deleteTodo={deleteTodo}/>
                    })
                }
            </ul>
        )
    }
}

List中的每一列,ITEM组件

import React, { Component } from 'react'

export default class item extends Component {
    state = {mouse:false}//标识鼠标移入移出

    handleMouse = (flag) =>{
        return ()=>{
           this.setState({mouse:flag})
        }
    }
    //勾选,取消勾选某一个todo的回调
    handleCheck = (id)=>{
        return (event)=>{
            this.props.updateTodo(id,event.target.checked)
        }
    }
    handleDelet = (id)=>{
        if(window.confirm('确定删除吗?')){
            this.props.deleteTodo(id)
        }
    }

    render() {
        const{id,name,done} = this.props
        const{mouse} = this.state
        return (
            <div>
                 <li style={{backgroundColor:mouse?'#ddd':'white'}} onMouseLeave={this.handleMouse(false)} onMouseEnter={this.handleMouse(true)}>
                  <label>
                    <input type="checkbox" checked={done} onChange={this.handleCheck(id)}/>
                    <span>{name}</span>
                  </label>
                  <button onClick={()=>(this.handleDelet(id))} className="btn btn-danger" style={{display:mouse?'block':'none'}}>删除</button>
                </li>
            </div>
        )
    }
}

最终,尾部组件

import React, { Component } from 'react'

export default class Footer extends Component {
  //全选checkbox的回调
  handleCheckAll = (event)=>{
    this.props.checkAllTodo(event.target.checked)
  }

  handleClearAllDone = ()=>{
    this.props.clearAllDone()
  }

    render() {
      const {todos} = this.props
      //计算已完成的个数
      const doneCount = todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0),0)
      //总数
      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>
                <span>已完成{doneCount}</span> / 全部{total}
              </span>
              <button onClick={this.handleClearAllDone} className="btn btn-danger">清除已完成任务</button>
            </div>
        )
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值