二、【React脚手架】组件化编码(TodoList案例)
创始人
2024-02-23 11:43:17

文章目录

  • 1、组件化编码流程(通用)
  • 2、样式覆盖问题
  • 3、DEMO
    • 3.1、需要实现的效果
    • 3.2、前期须知
    • 3.3、项目结构
    • 3.4、CODE
      • 3.4.1、App.js
      • 3.4.2、App.css
      • 3.4.3、Header
      • 3.4.4、List
      • 3.4.5、Item
      • 3.4.6、Footer

1、组件化编码流程(通用)

  1. 拆分组件: 拆分界面,抽取组件

  2. 实现静态组件: 使用组件实现静态页面效果

  3. 实现动态组件

    1. 动态显示初始化数据
      1. 数据类型
      2. 数据名称
      3. 保存在哪个组件?
    2. 交互(从绑定事件监听开始)

2、样式覆盖问题

  1. 使用 less,例如import '.\xxx.less',样式采用嵌套格式,顶级样式名不重即可,建议使用组件名
    1. 也可使用2的方法,此时不必写 .module
  2. css样式文件加 .module,例如 xxx.module.css
    1. 用参数命名引入这个样式文件: import styles from 'xxx.module.css'
    2. 使用时采用react插值方式:className={styles.xx}

3、DEMO

3.1、需要实现的效果

在这里插入图片描述

3.2、前期须知

  • 如果要对 props 进行限制,需要引入 prop-types 库

    • 安装指令:yarn add prop-types

    • 引入指令:import PropTypes from 'prop-types'

    • 使用限制:static propTypes = { addOne: PropTypes.func.isRequired }

    • 使用可参考 五、【React基础】组件实例三大核心属性之二 props 中 2、3 栏

  • id 需要使用不重复随机数,推荐使用nanoid

    • 安装指令:yarn add nanoid

    • 引入函数:import { nanoid } from 'nanoid'

    • 使用函数:nanoid()

3.3、项目结构

只有红框内的文件有修改或是新增的

在这里插入图片描述

3.4、CODE

3.4.1、App.js

import React, { Component } from 'react'
import { nanoid } from 'nanoid'
import Header from './components/ToDoList/Header'
import List from './components/ToDoList/List'
import Footer from './components/ToDoList/Footer'
import './App.css'export default class App extends Component {state = {todoList: [{id: '001',name: '吃饭',done: false}, {id: '002',name: '睡觉',done: false}, {id: '003',name: '打豆豆',done: false}]}toNever = id => {const { todoList } = this.statetodoList.map(item => {if (item.id === id) {item.done = !item.done}return item})this.setState({ todoList })}addOne = name => {const { todoList } = this.statethis.setState({todoList: [{id: nanoid(),name,done: false},...todoList]})}deleteById = id => {if (!window.confirm('确定删除吗?')) returnconst { todoList } = this.statethis.setState({ todoList: todoList.filter(item => item.id !== id) })}deleteDone = () => {if (!window.confirm('确定删除吗?')) returnconst { todoList } = this.statethis.setState({ todoList: todoList.filter(item => !item.done) })}doneAllOrNot = () => {const { todoList } = this.stateconst dones = todoList.filter(i => i.done).lengthtodoList.map(item => {item.done = !(todoList.length === dones)return item})this.setState({ todoList })}render() {return (
this.addOne} />...this.state} toNever={this.toNever} deleteById={this.deleteById} />
...this.state} doneAllOrNot={this.doneAllOrNot} deleteDone={this.deleteDone} />
);} }

3.4.2、App.css

/*base*/
body {background: #fff;
}.btn {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;display: none;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;display: flex;justify-content: space-between;
}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:hover .btn {display: block;
}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;
}.todo-footer:hover .btn {display: block;
}

3.4.3、Header

import React, { Component } from 'react'
import PropTypes from 'prop-types'export default class Header extends Component {static propTypes = {addOne: PropTypes.func.isRequired}add = e => {const { addOne } = this.propsif (e.key === 'Enter') {if (!!e.target.value.trim()) {addOne(e.target.value)e.target.value = ''} else {alert('请输入非空任务名')}}}render() {return (
this.add} />
)} }

3.4.4、List

import React, { Component } from 'react'
import Item from './Item'export default class List extends Component {render() {const { todoList, toNever, deleteById } = this.propsreturn (
    {todoList.map(item => item.id} todo={item} toNever={toNever} deleteById={deleteById} />)}
)} }

3.4.5、Item

import React, { Component } from 'react'export default class Item extends Component {render() {const { id, name, done } = this.props.todoconst { toNever, deleteById } = this.propsreturn (
  • )} }

    3.4.6、Footer

    import React, { Component } from 'react'export default class Footer extends Component {render() {const { todoList, doneAllOrNot, deleteDone } = this.propsconst total = todoList.lengthconst done = todoList.filter(item => item.done).lengthreturn (
    已完成{done || 0} / 全部{total || 0}
    )} }


    小白学习参考视频:尚硅谷React教程

    中文官网:React 官方中文文档

    相关内容

    热门资讯

    北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
    春风一拂千山绿 春风轻拂千山绿... 新春对联欣赏1、天意无常顺子自然,万般皆苦唯有自渡。2、门迎百福吉星照,户纳千祥鸿运开。3、一门天赐...
    世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
    应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...