app.js
//app.jsimport React,{useState} from "react"import Header from "./components/Header/index"import Search from "./components/Search"import cssObj from "./index.module.css"import Content from "./components/Content"import Footer from "./components/Footer"function App() { const [title]=useState("My Todo With React") return ( <div className={cssObj.app}> <Header title={title}/> <Search/> <Content/> <Footer/> </div> );}export default App;
//index.module.css.app{ /* position: absolute; left:50%; bottom: 50%; transform: translate(-50%,-50%); */ width: 500px; border:1px solid red; margin: 30px auto;}
封装button组件
//buttons.jsximport React, { Component } from 'react'import PropTypes from 'prop-types'import { Button } from 'antd';export default class index extends Component { static propTypes = { btnTitle: PropTypes.string } ClickHandle=(e)=>{ if( this.props.addHandle){ this.props.addHandle() } if(this.props.deleteHandle){ this.props.deleteHandle() } } render() { const {btnTitle}=this.props return ( <div> <Button type="primary" onClick={this.ClickHandle}>{btnTitle}</Button> </div> ) }
头部header
//header.jsximport React, { Component } from 'react'import PropTypes from 'prop-types'export default class index extends Component { static propTypes = { title: PropTypes.string } render() { const {title}=this.props return ( <div> <h1 style={{textAlign:'center',marginBottom:'20px',lineHeight:'35px',height:'30px'}}>{title}</h1> <hr/> </div> ) }}
内容部分content
//content.jsximport React, { Component} from 'react'import { Button} from 'antd';import './index.css'import PubSub from 'pubsub-js'export default class index extends Component { state = { arr: [{ id: 1, title: "天气不错", state: 0, num: 1, btn: '删除' }, { id: 2, title: "天气不错", state: 0, num: 1, btn: '删除' }, { id: 3, title: "天气不错", state: 1, num: 1, btn: '删除' }, { id: 4, title: "天气不错", state: 1, num: 1, btn: '删除' }, { id: 5, title: "天气不错", state: 1, num: 1, btn: '删除' } ], tag: 0 } setStateAsync(state) { return new Promise((resolve) => { this.setState(state, resolve) }); } componentDidMount() { //拿到全局的数据 let newArr = this.state.arr //添加操作的订阅器 this.submit = PubSub.subscribe('NewObj', async (msg, data) => { if (msg === 'NewObj') { await this.setStateAsync({ arr: [...this.state.arr, data] }) //拿到改变后全局的数据 newArr = this.state.arr } }); //筛选操作的订阅器 this.submitTag = PubSub.subscribe('tag', (msg, tag) => { let arrItem = [] if (tag === -1) { arrItem = newArr } else { arrItem = newArr.filter(item => item.state === tag) } this.setState({ arr: arrItem }) }); } //删除订阅器 componentWillUnmount() { PubSub.unsubscribe(this.submit); PubSub.unsubscribe(this.submitTag); } //删除操作 deleteHandle = (id) => { let index = this.state.arr.findIndex(item => { return item.id === id }) this.state.arr.splice(index, 1) this.setState({ arr: this.state.arr }) }//改变状态 change = (id) => { this.state.arr.forEach(item => { if (item.id === id) { item.state === 0 ? item.state = 1 : item.state = 0 } }) this.setState({ arr: [...this.state.arr] }) } render() { const {arr}=this.state return ( <div className="bodyStyle"> { arr.map(item=>{ return ( <ul className="contentStyle" key={item.id}> <li>{item.title}</li> <li className={item.state===0?'finsihState':'startState'} onClick={this.change.bind(this,item.id)}>{item.state===0?'未完成':'已完成'}</li> <li>{item.num}</li> <li> <Button onClick={this.deleteHandle.bind(this,item.id)} type="primary">{item.btn}</Button> </li> </ul> ) }) } </div> ) } }
.contentStyle{ display: flex; justify-content: space-evenly; align-content: center; list-style: none;}.finsihState{ text-decoration: line-through; cursor: pointer;}.startState{ cursor: pointer;}.bodyStyle{padding-top: 30px;}.contentStyle li{ height: 40px; line-height:40px;}
尾部footer
import React, { Component } from 'react'// import PropTypes from 'prop-types'import { Button } from 'antd';import "./index.css" import PubSub from 'pubsub-js' //引入export default class index extends Component { state={ list:[-1,1,0] } filterHandle=(tag)=>{ switch (tag) { case '全部': PubSub.publish('tag', tag) //发布消息 break; case '未完成': PubSub.publish('tag', tag) //发布消息 break; default: PubSub.publish('tag', tag) //发布消息 break; } } render() { const {list}=this.state return ( <div className="btnArea"> { list.map((item,index)=>{ return( <Button type="primary" key={index} onClick={this.filterHandle.bind(this,item)}>{item===-1?'全部':(item===0?'未完成':'已完成')}</Button> ) }) } </div> ) }}
.btnArea { display: flex; width: 100%; height: 50px; margin-top: 15px;align-items: center; justify-content: space-evenly;}
添加add
//add.jsximport React, { Component } from 'react'import Buttons from "../Buttons"import { Input,Row ,Col } from 'antd';import './index.css'import PubSub from 'pubsub-js' import {nanoid} from 'nanoid'export default class index extends Component { state={ add:'增加', value:'' } addHandle=()=>{ let NewObj= {id:nanoid(),title:this.state.value,state:0,num:1,btn:'删除'} PubSub.publish('NewObj',NewObj) //发布消息 this.setState({ value:'' }) } changeHandle=(e)=>{ this.setState({ value:e.target.value }) } render() { const {add,value}=this.state return ( <div className='inputAdd'> <Row> <Col span={5}> </Col> <Col span={12}> <Input placeholder="请输入搜索内容" value={value} onChange={this.changeHandle}/> </Col> <Col span={2}> <Buttons btnTitle={add} addHandle={this.addHandle}></Buttons> </Col> </Row> </div> ) }
.inputAdd{ margin-top: 20px;}
安装依赖
//antdyarn add antd//nanoid生成随机idyarn add nanoid//添加发布订阅yanrn add pubsub-js//类型校验yarn add prop-types
效果演示
