react todolist
组件容器(App.tsx)
import React,{Component} from 'react'
import Item from './js/Item'
import Footer from './js/Footer'
export default class App extends Component{
constructor(){
super();
this.state={
todoDatas:[],
todoNum:0,
view:"all",
flag:false
}
this.addTodo=this.addTodo.bind(this);
this.deleteTodo=this.deleteTodo.bind(this);
this.changeHasCompleted=this.changeHasCompleted.bind(this);
this.editTodo=this.editTodo.bind(this);
this.viewTodo=this.viewTodo.bind(this);
this.clearCompleted=this.clearCompleted.bind(this);
this.allSelectAll = this.allSelectAll.bind(this);
}
// 改变todo的状态
changeHasCompleted(todo){
let {todoDatas,todoNum}=this.state;
todoDatas=todoDatas.map(function(value,index){
if(todo.id==value.id){
value.hasCompleted=!todo.hasCompleted;
if(value.hasCompleted){
todoNum--;
}else{
todoNum++;
}
}
return value;
})
this.setState({todoDatas,todoNum})
}
// 过滤todo
viewTodo(view){
this.setState({
view
})
}
// 修改todo
editTodo(todo){
let {todoDatas}=this.state;
todoDatas=todoDatas.map((value)=>{
if(value.id==todo.id){
value.value=todo.value;
}
return value;
});
this.setState({todoDatas})
return true;
}
// 删除todo
deleteTodo(todo){
let {todoDatas}=this.state;
todoDatas=todoDatas.filter((value)=>{
if(value.id=todo.id){
return false;
}else{
return true;
}
})
this.setState({todoDatas})
}
addTodo(e) {
//判断如果不是回车,就不往下执行代码
if (e.keyCode != 13) return;
//如果文本框里面空字符串,就不往下执行代码
if (e.target.value.trim() === "") return;
//如果用户按的是回车并且不是空字符串,添加todo
console.log("addTodo");
//将状态todoDatas解构赋值到一个数组todoDatas中
let { todoDatas, todoNum } = this.state;
let todo = {};
todo.id = new Date().getTime();
// todo {id:2131232321}
todo.value = e.target.value.trim();
// todo {id:2131232321,value:"asdf"}
todo.hasCompleted = false;
//todo {id:2131232321,value:"asdf",hasCompleted:false}
//给解构出来的数组添加一个元素
todoDatas.push(todo);
todoNum++;
//更新this.state中的todoDatas中,引发重新render
this.setState({ todoDatas,todoNum});
//清除文本框里面的字符串
e.target.value = "";
}
// 删除已完成的todo
clearCompleted(){
// 数据过滤
let {todoDatas}=this.state;
todoDatas=todoDatas.filter((value)=>{
if(value.hasCompleted){
return false;
}else{
return true;
}
})
this.setState({
todoDatas
})
}
// 全选和全不选
allSelectAll(){
let {todoDatas,flag,todoNum}=this.state;
flag=!flag;
if(flag){
todoDatas=todoDatas.map((value)=>{
value.hasCompleted=true;
return value;
})
todoNum-0
}else{
todoDatas = todoDatas.map((value) => {
value.hasCompleted = false;
return value;
})
todoNum = todoDatas.length;
}
this.setState({ todoDatas, flag, todoNum });
}
render(){
let { addTodo, deleteTodo, changeHasCompleted, editTodo, viewTodo, clearCompleted, allSelectAll}=this;
let {todoDatas,todoNum,view}=this.state;
let filterTodo=todoDatas.filter((todo)=>{
switch(view){
case 'all':
return true;
case 'active':
return !todo.hasCompleted;
case 'completed':
return todo.hasCompleted;
}
})
let items=filterTodo.map((todo,index)=>{
return <Item
key={todo.id}
todo={todo}
deleteTodo={deleteTodo}
changeHasCompleted={changeHasCompleted}
editTodo={editTodo}
/>
});
return(
<section className="todoapp">
<header>
<h1>Todos</h1>
<input type="text"
className="new-todo"
placeholder="What need to do"
onKeyUp={addTodo}
/>
</header>
<section className="main">
<input
id="toggle-all"
type="checkbox"
className="toggle-all"
onChange={allSelectAll}
/>
<label htmlFor="toggle-all"></label>
<ul className="todo-list">
{items}
</ul>
</section>
<Footer
todoNum={todoNum}
viewTodo={viewTodo}
clearCompleted={clearCompleted}
/>
</section>
)
}
}
Item组件(todo)
import React, { Component } from 'react'
export default class Item extends Component {
constructor(){
super();
this.state={
inEdit:false, //标识是否进入编辑状态
flag:true //标识是否可以执行onBlur处理函数中的代码
}
this.haddleEdit=this.haddleEdit.bind(this);
}
haddleEdit(){
let {todo}=this.props;
let {inEdit}=this.state;
this.setState({
inEdit:true
},()=>{
//将当前todo.value赋值给文本框
this.refs.myInput.value=todo.value;
//让文本框获的焦点:原生js的模拟触发获得焦点
this.refs.myInput.focus();
})
}
render() {
let {todo,changeHasCompleted,editTodo,deleteTodo}=this.props;
let {inEdit,flag}=this.state;
let completed=todo.hasCompleted?"completed":"";
let className=inEdit?completed+" editing":completed;
return (
<li className={className}>
<div className="view">
<input type="checkbox" className="toggle"
onChange={()=>{
changeHasCompleted(todo);
}}
checked={todo.hasCompleted}
/>
<label onDoubleClick={this.haddleEdit}>{todo.value}</label>
<button className="destroy"
onClick={()=>{
deleteTodo(todo)
}}
></button>
</div>
<input ref="myInput" type="text" className="edit"
onBlur={(e)=>{
if(flag){
console.log("onBlur");
todo.value=e.target.value.trim();
editTodo(todo);
this.setState({
inEdit:false
})
}
}}
onKeyUp={(e)=>{
if(e.keyCode!=13 && e.keyCode!=27) return;
if(e.keyCode===13){
todo.value=e.target.value.trim();
editTodo(todo);
this.setState({
inEdit:false
})
}
if(e.keyCode===27){
editTodo(todo);
this.setState({
inEdit:false,
flag:false
})
setTimeout(()=>{
this.setState({
flag:true
})
},10)
}
}}
/>
</li>
)
}
}
Footer组件
import React, { Component } from 'react'
export default class Footer extends Component {
render() {
let{todoNum,viewTodo,clearCompleted}=this.props
return (
<footer className="footer">
<span className="todo-count">
<strong>{todoNum} {todoNum > 1 ? " items left" : " item left"}</strong>
</span>
<ul className="filters">
<li><a href="#/all" onClick={()=>viewTodo("all")}>All</a></li>
<li><a href="#/active" onClick={() => viewTodo("active")}>Active</a></li>
<li><a href="#/completed" onClick={() => viewTodo("completed")}>completed</a></li>
</ul>
<button className="clear-completed"
onClick={()=>clearCompleted()}
>Clear completed</button>
</footer>
)
}
}