React脚手架简介
快速构建模块化、组件化、工程化项目
创建项目步骤
1.npm i create-react-app -g
2.create-react-app react-demo
3.cd react-demo
4.npm start
TodoList案例
效果图
代码目录
App组件
import React, {
Component } from 'react'
import Header from './components/Header'
import List from './components/List'
import Footer from './components/Footer'
import './App.css'
export default class App extends Component {
state = {
todos:[
{
id:'1',name:'刷B站',done:true},
{
id:'2',name:'刷csdn',done:false},
{
id:'3',name:'刷小红书',done:false},
]}
//添加todo
addTodo = (todoObj)=>{
const {
todos} = this.state
const newTodos = [todoObj,...todos]
this.setState({
todos:newTodos})
}
//更新todo
updateTodo = (id,done)=>{
const {
todos} = this.state
const newTodos = todos.map((todoObj)=>{
if(todoObj.id === id) return {
...todoObj,done}
else return todoObj
})
this.setState({
todos:newTodos})
}
//删除todo
deleteTodo = (id)=>{
const {
todos} = this.state
const newTodos = todos.filter((todoObj)=>{
return todoObj.id !== id
})
this.setState({
todos:newTodos})
}
//全选todo
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
})
this.setState({
todos:newTodos})
}
// 渲染组件
render() {
const {
todos} = this.state
return (
<div className="todo-container">
<div className="todo-wrap">
<Header addTodo={
this.addTodo}/>
<List todos={
todos} updateTodo={
this.updateTodo} deleteTodo={
this.deleteTodo}/>
<Footer todos={
todos} checkAllTodo={
this.checkAllTodo} clearAllDone={
this.clearAllDone}/>
</div>
</div>
)
}
}
Header组件
import React, {
Component } from 'react'
import PropTypes from 'prop-types'
import {
nanoid} from 'nanoid'
import './index.css'
export default class Header extends Component {
static propTypes = {
addTodo:PropTypes.func.isRequired
}
//回车添加代办
handleKeyUp = (event)=>{
const {
keyCode,target} = event
if(keyCode !== 13) return
if(target.value.trim() === ''){
alert('输入不能为空')
return
}
const todoObj = {
id:nanoid(),name:target.value,done:false}
this.props.addTodo(todoObj)
target.value = ''
}
render() {
return (
<div className="todo-header">
<input onKeyUp={
this.handleKeyUp} type="text" placeholder="请输入待办"/>
</div>
)
}
}
List组件
import React, {
Component } from 'react'
import PropTypes from 'prop-types'
import Item from '../Item'
import './index.css'
export default class List extends Component {
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>
)
}
}
Iitem组件
import React, {
Component } from 'react'
import './index.css'
export default class Item extends Component {
state = {
mouse:false}
//鼠标移动
handleMouse = (flag)=>{
return ()=>{
this.setState({
mouse:flag})
}
}
//勾选
handleCheck = (id)=>{
return (event)=>{
this.props.updateTodo(id,event.target.checked)
}
}
//删除todo
handleDelete = (id)=>{
if(window.confirm('确定删除吗?')){
this.props.deleteTodo(id)
}
}
render() {
const {
id,name,done} = this.props
const {
mouse} = this.state
return (
<li style={
{
backgroundColor: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) } className="btn btn-danger" style={
{
display:mouse?'block':'none'}}>删除</button>
</li>
)
}
}
Footer组件
import React, {
Component } from 'react'
import './index.css'
export default class Footer extends Component {
//全选
handleCheckAll = (event)=>{
this.props.checkAllTodo(event.target.checked)
}
//清除已办
handleClearAllDone = ()=>{
this.props.clearAllDone()
}
render() {
const {
todos} = this.props
const doneCount = todos.reduce((pre,todo)=> pre + (todo.done ? 1 : 0),0)
const total = todos.length
return (
<div className="todo-footer">
<label>
<input type="checkbox" onChange={
this.handleCheckAll} checked={
doneCount === total && total !== 0 ? true : false}/>
</label>
<span>
<span>已完成{
doneCount}</span> / 全部{
total}
</span>
<button onClick={
this.handleClearAllDone} className="btn btn-danger">清除已完成任务</button>
</div>
)
}
}