app.js
//app.js
import 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.jsx
import 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.jsx
import 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.jsx
import 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.jsx
import 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;
}
安装依赖
//antd
yarn add antd
//nanoid生成随机id
yarn add nanoid
//添加发布订阅
yanrn add pubsub-js
//类型校验
yarn add prop-types
效果演示