效果如下:

分析組件:
1.頭部:標(biāo)題
2.內(nèi)容:列表項(xiàng)+刪除
3.尾部:添加列表項(xiàng)
4.包裹所有組件的App.js,在這個(gè)大的組件包含所有的屬性及操作

標(biāo)題
//header.js
import React,{Component } from 'react';
import "./header.css"
class Header extends Component{
render(){
return (
<div className="header">
任務(wù)便簽
</div>
)
}
}
export default Header
在App.js引出:
<Header />
尾部添加
分析:
1.因?yàn)樗械牟僮鞫紩?huì)在App.js里面去操作,所以子組件的所以初始化的屬性都需要通過(guò)父組件傳值給子組件;比如輸入框的value屬性值
2.通過(guò)onChange事件獲取用戶輸入的值,試想:怎么讓用戶輸入的值顯示在輸入框里面呢:也就是說(shuō)我怎么把輸入的值賦值給父組件的value,這就需要使用子組件觸發(fā)父組件的函數(shù),并傳值給父組件:this.props.這個(gè)方法(傳的值)
3.當(dāng)點(diǎn)擊添加按鈕的時(shí)候,我需要將輸入的值追加到定義的List,同樣在子組件點(diǎn)擊按鈕,觸發(fā)父組件的方法
footer.js
class Header extends Component{
handleInput(e){
this.props.handleInput(e.target.value)
}
handleAdd(){
this.props.handleAdd()
}
render(){
return (
<div className="footer">
<input type="text" value={this.props.value} onChange={this.handleInput.bind(this)}>
<button onChlick={this.handleAdd.bind(this)}>添加</button>
</div>
)
}
}
//父組件
constructor(props) {
super(props)
this.state = {
list: [{
name: 'learn english',
status: 0
}, {
name: 'Learn guitar',
status: 0
}, {
name: 'weight less than 100',
status: 0
}, {
name: 'have 100,000 deposit',
status: 0
}],
value:"",
}
}
//父組件接受子組件傳的值
handleInput(val){
this.setData({
value:val
})
}
handleAdd(){
if(!this.state.value){
return false
}
this.setState({
list:[...this.state.list,{
name:this.state.value,
status:0,
}],
value:""
})
}
render{
return (
<Footer value={this.state.list} handleInput={this.handleInput.bind(this)} handleAdd={this.handleAdd.bind(this)} />
)
}
中間列表項(xiàng)
分析:
1.列表項(xiàng)是由一個(gè)單選框,名字,刪除按鈕
2.因?yàn)榱斜眄?xiàng)可能會(huì)有很多,則使用map方法
3.單選框的選中狀態(tài)是由List的status為1才表示已選中,當(dāng)選中狀態(tài)發(fā)生改變時(shí),怎么讓list的status實(shí)時(shí)去改變呢,所以需要出發(fā)父組件的方法,
4.當(dāng)該列表項(xiàng)為選中時(shí),則該文字會(huì)加上刪除線:利用text-decoration-line:值為"line-through"時(shí)表示文字中間部分畫(huà)線
5.點(diǎn)擊刪除按鈕是需要?jiǎng)h除當(dāng)前用戶點(diǎn)擊的那一行,所以怎么判斷用戶是當(dāng)前那一行是一個(gè)問(wèn)題:
6.已完成的數(shù)量是表示status為1的個(gè)數(shù)
// this.handleclick.bind(this,要傳的參數(shù)) handleclick(傳過(guò)來(lái)的參數(shù),event)
class ListItem extends Component{
handleFished(name){
// 子組件向父組件傳值
// 在子組件點(diǎn)擊的li得到的值,交給父組件去做交互
this.props.handleFished(name);
}
handleDelete(name){
this.props.handleDelete(name)
}
render(){
return (
<ul>
{this.props.data.map((item,index)=>{
return (
<li key={index} className="listItem">
<input type="checkbox" checked={item.status===1} onChange={this.handleFished.bind(this,item.name)} />
<span style={{textDecorationLine:item.status===0?'none':'line-through'}}>{item.name}</span>
<button className="delete" onClick={this.handleDelete.bind(this,item.name)}>刪除</button>
</li>
)
})}
<li>已完成:{this.props.finished}/總數(shù):{this.props.data.length}</li>
</ul>
)
}
}
export default ListItem
父組件:
constructor(props) {
super(props)
this.state = {
list: [{
name: 'learn english',
status: 0
}, {
name: 'Learn guitar',
status: 0
}, {
name: 'weight less than 100',
status: 0
}, {
name: 'have 100,000 deposit',
status: 0
}],
finished:0,//已完成的個(gè)數(shù)
}
}
handleFished(name){
const list=[];
let sum=0;
this.state.list.forEach((item,index){
//判斷用戶點(diǎn)擊的是當(dāng)前所點(diǎn)擊的那一行
if(item.name=name){
let val=this.state.list[index]
let obj={
name:val.name,
status:val.status===0?1:0
}
list.push(Object.assign({},obj))
this.setState({
list:list
},()=>{
this.state.list.forEach(item=>{
if(item.status===1){
sum++;
}
this.setState({
finished:sum
})
})
})
} else{
list.push(item)
}
})
}
handleDelete(name){
let arr=this.state.list.filter((item)=>{
return item.name!==name
})
this.setState({
list:arr
})
}
render(){
return(
<ListItem data={this.state.list} finished={this.state.finished} handleFished={this.handleFished.bind(this)} handleDelete={this.handleDelete.bind(this)} />
)
}