Tolist案例(父子传参实现增删改)

1.Tolist案例(父子传参实现增删改)

目录结构

实现效果:

App.jsx

class App extends Component {
    // 状态在哪里, 操作状态的方法就在哪里
    state = {
        todos:[
            {id:1, name:'吃饭', done: true},
            {id:2, name:'睡觉', done: true},
            {id:3, name:'打代码', done: false},
            {id:4, name:'光街', done: true},
        ]
    }

    // addTodo用于添加一个todo, 接收的参数是todo对象
    addTodo = (todoObj) =>{
        const {todos} = this.state
        const newTodos = [todoObj, ...todos]
        this.setState({todos:newTodos})
    }

    // updateTodo用于更新一个todo对象
    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用于删除一个todo对象
    deleteTodo = (id) => {
        const {todos} = this.state
        const newTodos = todos.filter((todoObj)=>{
            // 将id不是要删除的todo,重新过滤到一个新数组
            return todoObj.id !== id
        })
        this.setState({
            todos:newTodos
        })
    }
    //checkAllTodo用于全选或者取消全选
    checkAllTodo = (done) => {
        const {todos} = this.state
        const newTodos = todos.map((todoObj)=>{
            return {...todoObj, done}
        })
        this.setState({
            todos:newTodos
        })
    }

    // 删除已完成的任务(done为true,删除已选中的,批量删除)
    clearAllDone = () => {
        const {todos} = this.state
        const newTodos = todos.filter(todoObj => {
            return !todoObj.done
        })
        this.setState({
            todos: newTodos
        })
    }


    render() {
        const {todos} = this.state
        return (
            <div className="todo-container">
                <div className="todo-wrap">
                    {/* 子传父 通过子调用父函数 传参 */}
                    <Headers addTodo={this.addTodo}/>
                    {/* 父传子 传参 */}
                    <List todos={todos} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo}/>
                    <Footer todos={todos} checkAllTodo={this.checkAllTodo} clearAllDone={this.clearAllDone}/>
                </div>
            </div>

        )
    }
}

Headers.jsx

class Headers extends Component{

    //对接收的props进行:类型、必要性的限制
	static propTypes = {
		addTodo:PropTypes.func.isRequired
	}

    // 键盘回车事件, 13是回车返回的唯一值
    handleKeyUp = (event) => {
        const {keyCode, target} = event
        if (keyCode !== 13 || target.value.trim() === '')  return
        const todoObj = {id:nanoid(), name:target.value, done:false}
        // 调用父组件函数,添加一个todoObj
        this.props.addTodo(todoObj)
        // 清空输入框
        target.value = ''
        // console.log(event.target.value, event.keyCode)

    }

    render() {
        return (
            <div className="todo-header">
                {/*监听键盘事件*/}
                <input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认"/>
            </div>
        )
    }
}

List.jsx

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
        return (
            <ul className="todo-main">
                {
                    todos.map(todo => {
                        return <Items key={todo.id} {...todo} updateTodo={updateTodo} deleteTodo={deleteTodo}/>
                    })
                }

            </ul>
        )
    }
}

Items.jsx

class Items extends Component {

    state = {mouse:false}  // 标识鼠标移入、移出

    //鼠标移入、移除的回调
    handleMouse = (flag) =>{
        // 函数柯里化
        return () =>{
            this.setState({mouse:flag})
        }
    }

    // 勾选、取消勾选某一个todo的回调
    handleCheck = (id) => {
        return (event)=>{
            this.props.updateTodo(id, event.target.checked)
            // console.log(id, event.target.checked)
        }

    }

    // 删除一个todo的回调
    handleDelete = (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.handleMouse(true)} onMouseLeave={this.handleMouse(false)}>
                <label>
                    <input type="checkbox" checked={done} onChange={this.handleCheck(id)}/>
                    <span>{name}</span>
                </label>
                <button onClick={()=>this.handleDelete(id)} className="btn btn-danger" style={{display: mouse? 'block': 'none'}}>删除</button>
            </li>
        )
    }
}

Footer.jsx

class Footer extends Component{

    handleCheckAll = (event) => {
        // 是否全选或者取消选中
        const done = event.target.checked
        this.props.checkAllTodo(done)
    }

    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 onChange={this.handleCheckAll} type="checkbox" checked={doneCount === total && total !== 0}/>
                        </label>
                        <span><span>已完成{doneCount}</span> / 全部{total}</span>
                        <button onClick={this.props.clearAllDone} className="btn btn-danger">清除已完成任务</button>
                    </div>
        )
    }
}

posted @ 2021-09-03 16:35  tomjoy  阅读(175)  评论(0编辑  收藏  举报