src/views/Todos.js
/*
Todos的模板
*/
import React from 'react'
import 'todomvc-common/base.css'
import 'todomvc-app-css/index.css'
class Todos extends React.Component {
constructor (props) {
super(props)
this.state = {
isAll: false,
currentType: 'all',
etitle: '',
todos: [{
id: 1,
etitle: '写代码',
done: false,
isEdit: false
}, {
id: 2,
etitle: '去K歌',
done: true,
isEdit: false
}]
}
this.titleRef = React.createRef()
}
componentDidMount () {
// 自己实现光标定位,也可以使用标准的autoFocus属性实现
this.titleRef.current.focus()
}
handleEtitle = (e) => {
this.setState({
etitle: e.target.value
})
}
handleEditEtile = (id, e) => {
// 控制数组中对应标题的变化
let todos = [...this.state.todos]
todos.some(item => {
if (item.id === id) {
// 把最新的输入内容进行更新
item.etitle = e.target.value
return true
}
return false
})
this.setState({
todos: todos
})
}
handleKeyup = (e) => {
// 回车键的数字标识是13
if (e.keyCode === 13) {
// 按了回车键:添加任务
let ids = this.state.todos.map(item => {
return item.id
})
let maxId = Math.max.apply(null, ids) + 1
let todo = {
id: maxId,
etitle: this.state.etitle,
done: false
}
// let todos = [...this.state.todos]
// todos.push(todo)
this.setState({
todos: [...this.state.todos, todo],
etitle: ''
})
}
}
handleDelete = (id) => {
// 控制删除操作
let todos = [...this.state.todos]
// 查找要删除的数据索引
let index = todos.findIndex(item => {
return item.id === id
})
// 根据索引删除数组的元素
todos.splice(index, 1)
this.setState({
todos: todos
})
}
handleCheck = (id) => {
// 点击每个条目的时候,需要把数据中的done属性进行取反
let todos = [...this.state.todos]
todos.some(item => {
if (item.id === id) {
// 找到后把对应done状态取反
item.done = !item.done
// 终止继续遍历
return true
}
return false
})
this.setState({
todos: todos
})
}
handleCheckAll = () => {
this.setState({
isAll: !this.state.isAll
}, () => {
// 控制所有的列表的选中状态
let todos = [...this.state.todos]
todos.forEach(item => {
item.done = this.state.isAll
})
this.setState({
todos: todos
})
})
}
// handleBlue = (id) => {
// // 编辑状态失去焦点触发
// let todos = [...this.state.todos]
// todos.some(item => {
// if (item.id === id) {
// // 找到后把对应done状态取反
// item.isEdit = !item.isEdit
// // 终止继续遍历
// return true
// }
// return false
// })
// this.setState({
// todos: todos
// })
// }
handleDoubleClick = (id, e) => {
// let input = e.target.parentNode.parentNode.children[1]
// 获取label元素的父元素的下一个兄弟元素 input
let input = e.target.parentNode.nextSibling
// e.persist()
setTimeout(() => {
// 页面已经显示input元素之后才控制获取焦点
input&&input.focus()
}, 0)
// 双击进入编辑状态;或者失去焦点是,取消编辑状态
let todos = [...this.state.todos]
todos.some(item => {
if (item.id === id) {
// 找到后把对应isEdit状态取反
item.isEdit = !item.isEdit
// 终止继续遍历
return true
}
return false
})
this.setState({
todos: todos
})
}
handleCount = () => {
// 计算剩余的没有完成的任务数量
let num = 0
this.state.todos.forEach(item => {
if (!item.done) {
// 没有完成的任务
num += 1
}
})
return num
}
handleFilter = (e) => {
// 更新当前的筛选条件
let id = e.target.dataset.id
if (!id) {
// 没有id,什么都不做
return
}
this.setState({
currentType: id
})
}
handleFilterData = () => {
let { todos, currentType } = this.state
return todos.filter(item => {
if (currentType === 'all') {
// 全部列表
return true
} else if (currentType === 'will' && !item.done) {
// 未完成
return true
} else if (currentType === 'done' && item.done) {
return true
} else {
return false
}
})
}
handleClearAll = () => {
// 清除所有的已完成任务
let todos = this.state.todos.filter(item => {
return !item.done
})
this.setState({
todos: todos
})
}
render () {
let { todos, etitle, isAll, currentType } = this.state
// 根据当前筛选条件,过滤出列表数据
todos = this.handleFilterData()
let todoTags = todos.map(item => (
<li key={item.id} className={[item.done?'completed':'', item.isEdit? 'editing': ''].join(' ')}>
<div className="view" onDoubleClick={this.handleDoubleClick.bind(this, item.id)}>
<input checked={item.done} onChange={this.handleCheck.bind(this, item.id)} className="toggle" type="checkbox"/>
<label>{item.etitle}</label>
<button className="destroy" onClick={this.handleDelete.bind(this, item.id)}></button>
</div>
<input value={item.etitle} onChange={this.handleEditEtile.bind(this, item.id)} onBlur={this.handleDoubleClick.bind(this,item.id)} className="edit" />
</li>
))
return (
<div>
<section className="todoapp">
<header className="header">
<h1>土豆丝</h1>
<input ref={this.titleRef} onKeyUp={this.handleKeyup} value={etitle} onChange={this.handleEtitle} className="new-todo" placeholder="你想做什么?" />
</header>
<section className="main">
<input defaultChecked={isAll} id="toggle-all" className="toggle-all" type="checkbox"/>
<label onClick={this.handleCheckAll} htmlFor="toggle-all">全部标记为完成</label>
<ul className="todo-list">
{todoTags}
</ul>
</section>
<footer className="footer">
<span className="todo-count">剩余<strong>{this.handleCount()}</strong>个任务</span>
<ul onClick={this.handleFilter} className="filters">
<li>
<a data-id='all' className={currentType==='all'?'selected': ''} href="#/">全选</a>
</li>
<li>
<a data-id='will' className={currentType==='will'?'selected': ''} href="#/active">未完成</a>
</li>
<li>
<a data-id='done' className={currentType==='done'?'selected': ''} href="#/completed">已完成</a>
</li>
</ul>
<button onClick={this.handleClearAll} className="clear-completed">清除所有已完成任务</button>
</footer>
</section>
<footer className="info">
<p>Double-click to edit a todo</p>
<p>Template by <a href="http://sindresorhus.com">Sindre Sorhus</a></p>
<p>Created by <a href="http://todomvc.com">you</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
</div>
)
}
}
export default Todos