0


<前端组件化>拆分组件思想--吃饭、睡觉、打代码案例(附源码)

👏欢迎来到我的React系列文章
🍭本系列文章从React入门开始,涵盖了React的一切基础,属于是从零开始的一个系列
🍭文章会以图文结合-动图-代码实现-解释代码的形式带领大家走进React的世界
🍭持续更新中~希望大家能够喜欢,系列文章👉React–从基础到实战
🌈博客主页👉codeMak1r的博客
👉关注✨点赞👍收藏📂

  1. 🔥React入门与概览(JSX语法)
  2. 🔥面向组件编程——组件实例的三大核心属性state、props和refs超详解
  3. 🔥受控组件与非受控组件(vue和react的双向绑定分别是怎么实现的?)
  4. 🔥React函数的柯里化(什么?这玩意儿不仅能装x,还能优化代码?)
  5. 🔥四行代码让我的cpu跑上90度——走进组件生命周期
  6. 🔥图文详解react组件生命周期——React v16.8
  7. 🔥react新生命周期图文详解——最新版
  8. 🔥react-getSnapshotBeforeUpdate()生命周期函数详解
  9. 🔥使用create-react-app(CRA)创建react项目
  10. 🔥react父子组件传值(通信)
  11. 🔥<前端组件化>拆分组件思想-吃饭、睡觉、打代码案例(附源码)(👈本文)

本例使用的是React v18.1技术栈

文章目录

在这里插入图片描述

🏆组件的组合使用-TodoList

功能: 组件化实现此功能

1.显示所有todo列表

2.输入文本,点击按钮显示到列表的首位,并清除输入的文本
在这里插入图片描述

▶️拆分组件

在这里插入图片描述

📎项目结构

在这里插入图片描述

📌index.js

import React from'react';import ReactDOM from'react-dom/client';import App from'./App';const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<React.StrictMode><App /></React.StrictMode>);

📌App.jsx

在这里插入图片描述

import React,{ Component }from'react';import Header from'./components/Header';import List from'./components/List';import Footer from'./components/Footer';import'./App.css'classAppextendsComponent{// 状态在哪里,操作状态的方法就在哪里

  state ={todos:[{id:'001',name:'吃饭',done:true},{id:'002',name:'睡觉',done:true},{id:'003',name:'打代码',done:false},{id:'004',name:'逛街',done:true}]}// addTodo用于添加一个todo,接受的参数是todo对象addTodo=(todoObj)=>{const{ todos }=this.state
    const newTodos =[todoObj,...todos]this.setState({todos: newTodos });}// 用于勾选和取消勾选todoupdateTodo=(id, done)=>{// 获取todosconst{ todos }=this.state
    // 匹配处理数据const newTodos = todos.map((todoObj)=>{if(todoObj.id === id)return{...todoObj, done }elsereturn todoObj
    })this.setState({todos: newTodos });}// 用于删除一个tododeleteTodo=(id)=>{const{ todos }=this.state
    // 删除指定ID的todo对象const newTodos = todos.filter((todoObj)=>{// 数组的过滤方法,返回id不等于传进来的id值的那些todoObj对象,说明排除掉了点击了删除id对应的那个todoObjreturn todoObj.id !== id
    })this.setState({todos: newTodos });}// 用于全选checkAllTodo=(done)=>{const{ todos }=this.state
    const newTodos = todos.map((todoObj)=>{return{...todoObj, done }})this.setState({todos: newTodos });}// 用于清除已完成任务clearAllDone=()=>{const{ todos }=this.state
    // 过滤数据const newTodos = todos.filter((todoObj)=>{return todoObj.done !==true})this.setState({todos: newTodos });}render(){return(<div className="todo-container"><div className="todo-wrap"><Header addTodo={this.addTodo}/><List todos={this.state.todos} 
                  updateTodo={this.updateTodo} 
                  deleteTodo={this.deleteTodo}/><Footer todos={this.state.todos} 
                    checkAllTodo={this.checkAllTodo} 
                    clearAllDone={this.clearAllDone}/></div></div>);}}exportdefault App;

📌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部分

在这里插入图片描述

🛠Header-index.jsx

import React,{ Component }from'react';import PropTypes from'prop-types';import{ nanoid }from'nanoid'import'./index.css'classHeaderextendsComponent{// 键盘事件的回调handleKeyUp=(event)=>{if(event.key !=='Enter')return
    console.log(event.target.value, event.keyCode, event.key)// 添加的todo名字不能为空if(event.target.value.trim()===''){alert('输入不能为空')return}const todoObj ={id:nanoid(),name: event.target.value,done:false}this.props.addTodo(todoObj)// 清空输入框
    event.target.value =''}// 对接收的props进行类型限制static propTypes ={addTodo: PropTypes.func.isRequired,}render(){return(<div className="todo-header"><input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认"/></div>);}}exportdefault Header;

🛠Header-index.css

/*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);}

List部分

在这里插入图片描述

🛠List-index.jsx

import React,{ Component }from'react';import PropTypes from'prop-types';import Item from'../Item';import'./index.css'classListextendsComponent{// 对接收的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<Item key={todo.id}{...todo} 
                        updateTodo={updateTodo} 
                        deleteTodo={deleteTodo}/>})}</ul>);}}exportdefault List;

🛠List-index.css

/*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部分

在这里插入图片描述

🛠Item-index.jsx

import React,{ Component }from'react';import'./index.css'classItemextendsComponent{// 标识鼠标移入、移出
  state ={mouse:false}// 鼠标移入移出的回调handleMouse=(flag)=>{return()=>{this.setState({mouse: flag });}}// checkbox勾选的回调handleCheck=(id)=>{return(event)=>{
      console.log(id, event.target.checked)this.props.updateTodo(id, event.target.checked)}}// 删除一个todo的回调handleDelete=(id, name)=>{return()=>{if(window.confirm('确定删除'+ name +'吗?')){this.props.deleteTodo(id)}}}render(){const{ id, name, done }=this.props
    return(<li style={{backgroundColor:this.state.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, name)} 
                className="btn btn-danger" 
                style={{display:this.state.mouse ?'block':'none'}}>删除</button></li>);}}exportdefault Item;

🛠Item-index.css

/*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部分

在这里插入图片描述

🛠Footer-index.jsx

import React,{ Component }from'react';import'./index.css'classFooterextendsComponent{// 全选checkbox的回调handleCheckAll=(event)=>{
    console.log(event.target.checked)this.props.checkAllTodo(event.target.checked)}// 清除所有已完成任务的回调handleClearAllDone=()=>{this.props.clearAllDone()}render(){const{ todos }=this.props
    // 已完成的个数const doneCount = todos.reduce((prev, currentTodo)=>{return prev +(currentTodo.done ?1:0)},0)// 总数const total = todos.length

    return(<div className="todo-footer"><label><input type="checkbox" 
                  checked={doneCount === total && total !==0?true:false} 
                  onChange={this.handleCheckAll}/></label><span><span>已完成{doneCount}</span>/ 全部{total}</span><button onClick={this.handleClearAllDone} 
                className="btn btn-danger">清除已完成任务</button></div>);}}exportdefault Footer;

🛠Footer-index.css

/*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;}

✅案例总结

案例总结:

  1. 拆分组件,实现静态组件,注意:className、style的写法
  2. 动态初始化列表,如何确定将数据放在哪个组件的state中? - ——某个组件使用:放在自身state中- ——某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升)
  3. 关于父子组件的通信:(👉父子组件通信详解) - 【父组件】给【子组件】传递数据:通过props传递- 【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递一个函数
  4. 注意 defaultCheckedchecked 的区别,类似的还有:defaultValuevalue
  5. 状态在哪里,操作状态的方法就在哪里

好啦~今天的案例分享就到这里了,如果有疑问或者文章出现错误的话请一定要联系我哟😎😎~

非常感谢你的阅读,你的支持将会是我最大的动力

👉关注✨点赞👍收藏📂

回见~

在这里插入图片描述


本文转载自: https://blog.csdn.net/Svik_zy/article/details/125133147
版权归原作者 codeMak1r. 所有, 如有侵权,请联系我们删除。

“<前端组件化>拆分组件思想--吃饭、睡觉、打代码案例(附源码)”的评论:

还没有评论