likes
comments
collection
share

react函数式组件写todolist(原生)

作者站长头像
站长
· 阅读数 2

最终结果:

react函数式组件写todolist(原生)

第一步. 布置结构, 如下这样

react函数式组件写todolist(原生)

每一个文件夹里面都有一个index.jsx与index.css

react函数式组件写todolist(原生)

第二步. 实现列表显示页面

1.先在App.jsx里面初始化数据

2.把App.jsx里面的todo通过List.jsx组件传给item.jsx以显示列表数据

第三步. 实现新增功能

1.在App.jsx里面写一个添加一个对象的方法addTodo,将addTodo方法给Header.jsx组件,Header.jsx组件通过这个方法拿到input里面的值作为一个对象传为App.jsx 2.子组件中需要判断是否是回车按钮以及值是否为空,为空显示出一个弹窗不能为空

第四步.勾选与取消功能

App.jsx中定义一个勾选与取消的方法chekedTodo,通过List.jsx传给item.jsx,拿到input的id与当前的值给父组件,去判断拿到的id与原本的数据中的每一个id对比是否一致,一致的话,就改变当前的done的状态并且把状态值与以前的todo合并起来,否则就原封不动,最后把更新后的值重新设置一下

第五步.删除一个todo

App.jsx里面设置删除方法,通过这个方法传给item.jsx去绑定到button按钮上,拿到当前要删除的id,通过filter得到id不相等的对象显示到列表上

第六步. 清除已经勾选的功能

App.jsx里面设置特定的方法,将todoObj.done为true的删除

第七步. 全选

App.jsx设置方法拿到子组件里面的done,把当前的值true或false给原数据的每一个todo

//App.jsx
import Header from './Header'
import Footer from './Footer'
import List from './List'
import { useState } from 'react';
export default function App() {
  // 初始化数据
  const [todos, setTodos] = useState([
    { id: '01', name: '吃饭', done: true },
    { id: '02', name: '睡觉', done: true },
    { id: '03', name: '打代码', done: false },
    { id: '04', name: '打代码111', done: true }
  ])
  // 添加一个todo对象,并且更新状态
  const addTodo = (todoObj) => {
    setTodos([...todos, todoObj])
  }
  // 勾选与取消,并且更新状态
  const checkedTodo = (id, done) => {
    // 判断子组件传过来的值与父组件原本的值的id, 相等的话就是找到了选中的,返回原本的值并且覆盖done
    const newTodos = todos.map(todo => {
      if (todo.id == id) {
        return { ...todo, done }
      }
      // 不等就原封不动的返回原值
      else {
        return todo
      }
    })
    setTodos(newTodos)
  }

  // 删除一个todo
  const deleteTodo = (id) => {
    const newTodos = todos.filter(todo => todo.id !== id)
    setTodos(newTodos)
  }
  // 全选
  const checkAllTodo = (done) => {
    const newTodos = todos.map(todo => {
      // 注意点:3
        return { ...todo, done }
    })
    setTodos(newTodos)
  }
  // 清除已经勾选的
  const clearTodos = () => {
    const newTodos = todos.filter(todoObj => {
      return !todoObj.done
    })
    setTodos(newTodos)
  }
  return (
    <div className="todo-wrap">
      <Header addTodo={addTodo} />
      <List todos={todos} checkedTodo={checkedTodo} deleteTodo={deleteTodo} />
      <Footer todos={todos} checkAllTodo={checkAllTodo} clearTodos={clearTodos} />
    </div>
  )
}
// Header.jsx
export default function Header({addTodo}){
    const handleAdd = (event) => {
        // 判断并且拿到值传给父组件
        const {keyCode, target} = event
        if(keyCode !== 13) return
        // 判断不能为空
        if(target.value == ''){
            alert('不能为空')
            return
        }
        const newTodoObj = {id: nanoid(), name: target.value, done:false}
        addTodo(newTodoObj)
        // 清空input框
        target.value = ''
    }
    return (
        <div className="todo-header">
            <input type="text" placeholder="请输入你的任务名称,按回车键确认" onKeyUp={handleAdd}/>
        </div>
    )
}

// Footer.jsx
export default function Footer({todos, checkAllTodo, clearTodos}){
  // 已完成变量
  const doneCount = todos.reduce((pre, current)=> pre+(current.done?1:0), 0)
  const handleCheckedAll = (event) =>{
    checkAllTodo(event.target.checked)
  }
  return (
    <div className="todo-footer">
      <label>
      <input type="checkbox" onChange={handleCheckedAll} checked={doneCount == todos.length && todos.length !== 0? true : false}/>
      </label>
      <span>
      <span>已完成{doneCount}</span> / 全部{todos.length}
      </span>  
      {/* 1 */}
      <button className="btn btn-danger" onClick={()=>clearTodos()}>清除已完成任务</button>
    </div>
  )
}
// List.jsx
export default function List({todos, checkedTodo, deleteTodo}){
    return (
        <ul className="todo-main">
            {
                todos.map(todo=>{
                    return <Item {...todo} key={todo.id} checkedTodo={checkedTodo} deleteTodo={deleteTodo}/>
                })
            }
        </ul>
    )
}
// item.jsx
export default function Item({ id, name, done, deleteTodo, checkedTodo }) {
  // 鼠标的移入与移出
  const [mouse, setMouse] = useState(false)
  const handleMouse = (flag) => {
    setMouse(flag)
  }
  return (
    <li onMouseEnter={() => handleMouse(true)} onMouseLeave={() => handleMouse(false)}>
      <label>
        <input type="checkbox" onChange={(e) => checkedTodo(id, e.target.checked)} checked={done} />
        <span>{name}</span>
      </label>
      <button className="btn btn-danger" onClick={() => deleteTodo(id)} style={{ display: mouse ? 'block' : 'none' }}>删除</button>
    </li>
  )
}