app.js

  1. //app.js
  2. import React,{useState} from "react"
  3. import Header from "./components/Header/index"
  4. import Search from "./components/Search"
  5. import cssObj from "./index.module.css"
  6. import Content from "./components/Content"
  7. import Footer from "./components/Footer"
  8. function App() {
  9. const [title]=useState("My Todo With React")
  10. return (
  11. <div className={cssObj.app}>
  12. <Header title={title}/>
  13. <Search/>
  14. <Content/>
  15. <Footer/>
  16. </div>
  17. );
  18. }
  19. export default App;
  1. //index.module.css
  2. .app{
  3. /* position: absolute;
  4. left:50%;
  5. bottom: 50%;
  6. transform: translate(-50%,-50%); */
  7. width: 500px;
  8. border:1px solid red;
  9. margin: 30px auto;
  10. }

封装button组件

  1. //buttons.jsx
  2. import React, { Component } from 'react'
  3. import PropTypes from 'prop-types'
  4. import { Button } from 'antd';
  5. export default class index extends Component {
  6. static propTypes = {
  7. btnTitle: PropTypes.string
  8. }
  9. ClickHandle=(e)=>{
  10. if( this.props.addHandle){
  11. this.props.addHandle()
  12. }
  13. if(this.props.deleteHandle){
  14. this.props.deleteHandle()
  15. }
  16. }
  17. render() {
  18. const {btnTitle}=this.props
  19. return (
  20. <div>
  21. <Button type="primary" onClick={this.ClickHandle}>{btnTitle}</Button>
  22. </div>
  23. )
  24. }

头部header

  1. //header.jsx
  2. import React, { Component } from 'react'
  3. import PropTypes from 'prop-types'
  4. export default class index extends Component {
  5. static propTypes = {
  6. title: PropTypes.string
  7. }
  8. render() {
  9. const {title}=this.props
  10. return (
  11. <div>
  12. <h1 style={{textAlign:'center',marginBottom:'20px',lineHeight:'35px',height:'30px'}}>{title}</h1>
  13. <hr/>
  14. </div>
  15. )
  16. }
  17. }

内容部分content

  1. //content.jsx
  2. import React, {
  3. Component
  4. } from 'react'
  5. import {
  6. Button
  7. } from 'antd';
  8. import './index.css'
  9. import PubSub from 'pubsub-js'
  10. export default class index extends Component {
  11. state = {
  12. arr: [{
  13. id: 1,
  14. title: "天气不错",
  15. state: 0,
  16. num: 1,
  17. btn: '删除'
  18. },
  19. {
  20. id: 2,
  21. title: "天气不错",
  22. state: 0,
  23. num: 1,
  24. btn: '删除'
  25. },
  26. {
  27. id: 3,
  28. title: "天气不错",
  29. state: 1,
  30. num: 1,
  31. btn: '删除'
  32. },
  33. {
  34. id: 4,
  35. title: "天气不错",
  36. state: 1,
  37. num: 1,
  38. btn: '删除'
  39. },
  40. {
  41. id: 5,
  42. title: "天气不错",
  43. state: 1,
  44. num: 1,
  45. btn: '删除'
  46. }
  47. ],
  48. tag: 0
  49. }
  50. setStateAsync(state) {
  51. return new Promise((resolve) => {
  52. this.setState(state, resolve)
  53. });
  54. }
  55. componentDidMount() {
  56. //拿到全局的数据
  57. let newArr = this.state.arr
  58. //添加操作的订阅器
  59. this.submit = PubSub.subscribe('NewObj', async (msg, data) => {
  60. if (msg === 'NewObj') {
  61. await this.setStateAsync({
  62. arr: [...this.state.arr, data]
  63. })
  64. //拿到改变后全局的数据
  65. newArr = this.state.arr
  66. }
  67. });
  68. //筛选操作的订阅器
  69. this.submitTag = PubSub.subscribe('tag', (msg, tag) => {
  70. let arrItem = []
  71. if (tag === -1) {
  72. arrItem = newArr
  73. } else {
  74. arrItem = newArr.filter(item => item.state === tag)
  75. }
  76. this.setState({
  77. arr: arrItem
  78. })
  79. });
  80. }
  81. //删除订阅器
  82. componentWillUnmount() {
  83. PubSub.unsubscribe(this.submit);
  84. PubSub.unsubscribe(this.submitTag);
  85. }
  86. //删除操作
  87. deleteHandle = (id) => {
  88. let index = this.state.arr.findIndex(item => {
  89. return item.id === id
  90. })
  91. this.state.arr.splice(index, 1)
  92. this.setState({
  93. arr: this.state.arr
  94. })
  95. }
  96. //改变状态
  97. change = (id) => {
  98. this.state.arr.forEach(item => {
  99. if (item.id === id) {
  100. item.state === 0 ? item.state = 1 : item.state = 0
  101. }
  102. })
  103. this.setState({
  104. arr: [...this.state.arr]
  105. })
  106. }
  107. render() {
  108. const {arr}=this.state
  109. return (
  110. <div className="bodyStyle">
  111. {
  112. arr.map(item=>{
  113. return (
  114. <ul className="contentStyle" key={item.id}>
  115. <li>{item.title}</li>
  116. <li className={item.state===0?'finsihState':'startState'} onClick={this.change.bind(this,item.id)}>{item.state===0?'未完成':'已完成'}</li>
  117. <li>{item.num}</li>
  118. <li>
  119. <Button onClick={this.deleteHandle.bind(this,item.id)} type="primary">{item.btn}</Button>
  120. </li>
  121. </ul>
  122. )
  123. })
  124. }
  125. </div>
  126. )
  127. }
  128. }
  1. .contentStyle{
  2. display: flex;
  3. justify-content: space-evenly;
  4. align-content: center;
  5. list-style: none;
  6. }
  7. .finsihState{
  8. text-decoration: line-through;
  9. cursor: pointer;
  10. }
  11. .startState{
  12. cursor: pointer;
  13. }
  14. .bodyStyle{
  15. padding-top: 30px;
  16. }
  17. .contentStyle li{
  18. height: 40px;
  19. line-height:40px;
  20. }

尾部footer

  1. import React, { Component } from 'react'
  2. // import PropTypes from 'prop-types'
  3. import { Button } from 'antd';
  4. import "./index.css"
  5. import PubSub from 'pubsub-js' //引入
  6. export default class index extends Component {
  7. state={
  8. list:[-1,1,0]
  9. }
  10. filterHandle=(tag)=>{
  11. switch (tag) {
  12. case '全部':
  13. PubSub.publish('tag', tag) //发布消息
  14. break;
  15. case '未完成':
  16. PubSub.publish('tag', tag) //发布消息
  17. break;
  18. default:
  19. PubSub.publish('tag', tag) //发布消息
  20. break;
  21. }
  22. }
  23. render() {
  24. const {list}=this.state
  25. return (
  26. <div className="btnArea">
  27. {
  28. list.map((item,index)=>{
  29. return(
  30. <Button type="primary" key={index} onClick={this.filterHandle.bind(this,item)}>{item===-1?'全部':(item===0?'未完成':'已完成')}</Button>
  31. )
  32. })
  33. }
  34. </div>
  35. )
  36. }
  37. }
  1. .btnArea {
  2. display: flex;
  3. width: 100%;
  4. height: 50px;
  5. margin-top: 15px;
  6. align-items: center;
  7. justify-content: space-evenly;
  8. }

添加add

  1. //add.jsx
  2. import React, { Component } from 'react'
  3. import Buttons from "../Buttons"
  4. import { Input,Row ,Col } from 'antd';
  5. import './index.css'
  6. import PubSub from 'pubsub-js'
  7. import {nanoid} from 'nanoid'
  8. export default class index extends Component {
  9. state={
  10. add:'增加',
  11. value:''
  12. }
  13. addHandle=()=>{
  14. let NewObj= {id:nanoid(),title:this.state.value,state:0,num:1,btn:'删除'}
  15. PubSub.publish('NewObj',NewObj) //发布消息
  16. this.setState({
  17. value:''
  18. })
  19. }
  20. changeHandle=(e)=>{
  21. this.setState({
  22. value:e.target.value
  23. })
  24. }
  25. render() {
  26. const {add,value}=this.state
  27. return (
  28. <div className='inputAdd'>
  29. <Row>
  30. <Col span={5}>
  31. </Col>
  32. <Col span={12}>
  33. <Input placeholder="请输入搜索内容" value={value} onChange={this.changeHandle}/>
  34. </Col>
  35. <Col span={2}>
  36. <Buttons btnTitle={add} addHandle={this.addHandle}></Buttons>
  37. </Col>
  38. </Row>
  39. </div>
  40. )
  41. }
  1. .inputAdd{
  2. margin-top: 20px;
  3. }

安装依赖

  1. //antd
  2. yarn add antd
  3. //nanoid生成随机id
  4. yarn add nanoid
  5. //添加发布订阅
  6. yanrn add pubsub-js
  7. //类型校验
  8. yarn add prop-types

效果演示

20210407_160941.mp4 (1.89MB)