用react实现基础的ToDolist
上一次学会了如何构建一个基础的react框架,今天就来尝试写一个ToDolist锻炼一下自己的逻辑能力
首先我们要先构建好一个基础框架填上两组默认数据
import React, {
Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
list: [
{
title: 'react', done: true },
{
title: 'react2', done: false }
]
}
}
render() {
return (
<div>
<p>ToDolist</p>
</div>
);
}
}
export default App;
这样我们的页面上就显示出了ToDolist的字样,接下来对数据进行渲染和引用。
import React, {
Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
list: [
{
title: 'react', done: true },
{
title: 'react2', done: false }
]
}
}
render() {
return (
<div>
<p>ToDolist</p>
{
this.state.list.map(item => <div className='item' key={
item.title}>
<input type="checkbox" />
<span>{
item.title}</span>
<button>x</button>
</div>)}
</div>
);
}
}
export default App;
这样我们的页面上就会显示两个具备基础信息的list标签了,如图所示:
接下来让我们先实现删除功能,给button加上点击事件,并且传递参数:
<div>
<p>ToDolist</p>
{
this.state.list.map(item => <div className='item' key={
item.title}>
<input type="checkbox" />
<span>{
item.title}</span>
<button onClick={
this.delItem.bind(this, item)}>x</button>
</div>)}
</div>
在render()上方编写delItem方法
delItem = item => {
var list = this.state.list; //缓存list后续代码调用方便
var ind = list.findIndex(value => value.title === item.title);//查找和参数title值一样的list的下标
list.splice(ind, 1);//删除对应元素
this.setState({
list })//更新list
}
好了回到我们的页面就可以实现元素的删除了。
接下来我们实现一下筛选事件的功能,把已完成的事情和待完成的事件分成两类,首先我们要对list进行过滤处理,这里就要用到filter过滤方法了
<div>
<p>ToDolist</p>
<h3>正在进行{
this.state.list.filter(item => !item.done).length}</h3>
//过滤出list中done为false的个数(filter过滤出true时会返回,取反为true说明本来是false,这里有点绕,可以抽象的理解为双重否定表肯定)
{
this.state.list.map(item => <div className='item' key={
item.title}>
<input type="checkbox" />
<span>{
item.title}</span>
<button onClick={
this.delItem.bind(this, item)}>x</button>
</div>)}
</div>
这样我们就得到了未完成的任务数,同理可以过滤出已完成的任务数:
<div>
<p>ToDolist</p>
<h3>正在进行{
this.state.list.filter(item => !item.done).length}</h3>
//过滤出list中done为false的个数(filter过滤出true时会返回,取反为true说明本来是false,这里有点绕,可以抽象的理解为双重否定表肯定)
{
this.state.list.map(item => <div className='item' key={
item.title}>
<input type="checkbox" />
<span>{
item.title}</span>
<button onClick={
this.delItem.bind(this, item)}>x</button>
</div>)}
<h3>已经完成{
this.state.list.filter(item => item.done).length}</h3>
</div>
得到了如下的效果:
数量已经筛选出来了,但是任务的分类并没有到达正确的位置,这样我们只需要在渲染前对list数据过滤一下就好了代码如下:
<div>
<p>ToDolist</p>
<h3>正在进行{
this.state.list.filter(item => !item.done).length}</h3>
//过滤出list中done为false的个数(filter过滤出true时会返回,取反为true说明本来是false,这里有点绕,可以抽象的理解为双重否定表肯定)
{
this.state.list..filter(item => !item.done).map(item => <div className='item' key={
item.title}>
<input type="checkbox" />
<span>{
item.title}</span>
<button onClick={
this.delItem.bind(this, item)}>x</button>
</div>)}
<h3>已经完成{
this.state.list.filter(item => item.done).length}</h3>
{
this.state.list..filter(item => item.done).map(item => <div className='item' key={
item.title}>
<input type="checkbox" />
<span>{
item.title}</span>
<button onClick={
this.delItem.bind(this, item)}>x</button>
</div>)}
</div>
好了,这样每个list都有了自己正确的位置:
现在完成点击前面的小方块改变任务状态,并且把input状态和任务状态进行绑定,首先给前面的input添加点击事件:
<div>
<p>ToDolist</p>
<h3>正在进行{
this.state.list.filter(item => !item.done).length}</h3>
{
this.state.list.filter(item => !item.done).map(item => <div className='item' key={
item.title}>
<input type="checkbox" checked={
item.done} onChange={
this.checkItem.bind(this, item)} />
<span>{
item.title}</span>
<button onClick={
this.delItem.bind(this, item)}>x</button>
</div>)}
<h3>已经完成{
this.state.list.filter(item => item.done).length}</h3>
{
this.state.list.filter(item => item.done).map(item => <div className='item' key={
item.title}>
<input type="checkbox" checked={
item.done} onChange={
this.checkItem.bind(this, item)} />
<span>{
item.title}</span>
<button onClick={
this.delItem.bind(this, item)}>x</button>
</div>)}
</div>
已经实现了属性绑定,接下来编写函数,整体和删除的方法差不多都是查找到对应元素之后进行对应的操作代码如下:
checkItem = item => {
var list = this.state.list; //缓存list后续代码调用方便
var ind = list.findIndex(value => value.title === item.title);//查找和参数title值一样的list的下标
list[ind].done = !list[ind].done;//对于相应下标list的input确认进行取反
this.setState({
list })//更新list
}
回到页面就可以点击进行分类了
接下来实现添加功能,这里需要引用react的createRef方法进行节点的获取
import React, {
Component, createRef } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
list: [
{
title: 'react', done: true },
{
title: 'react2', done: false }
]
}
this.tempRef = createRef();
之后我们在页面添加一个input内容进行节点绑定,按钮绑定添加事件,最后更新list数据就OK了。
import React, {
Component, createRef } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
list: [
{
title: 'react', done: true },
{
title: 'react2', done: false }
]
}
this.tempRef = createRef();
}
delItem = item => {
var list = this.state.list; //缓存list后续代码调用方便
var ind = list.findIndex(value => value.title === item.title);//查找和参数title值一样的list的下标
list.splice(ind, 1);//删除对应元素
this.setState({
list })//更新list
}
checkItem = item => {
var list = this.state.list; //缓存list后续代码调用方便
var ind = list.findIndex(value => value.title === item.title);//查找和参数title值一样的list的下标
list[ind].done = !list[ind].done;//对于相应下标list的input确认进行取反
this.setState({
list })//更新list
}
addItem = () => {
var list = this.state.list;//缓存list后续代码调用方便
var inp = this.tempRef.current;//缓存input
list.unshift({
title: inp.value, done: false });//给list添加新的元素默认值为未完成false
this.setState({
list })//更新list
inp.value = ''
}
render() {
return (
<div>
<p>ToDolist</p>
<input type="text" ref={
this.tempRef} />
<button onClick={
this.addItem}>添加</button>
<h3>正在进行{
this.state.list.filter(item => !item.done).length}</h3>
{
this.state.list.filter(item => !item.done).map(item => <div className='item' key={
item.title}>
<input type="checkbox" checked={
item.done} onChange={
this.checkItem.bind(this, item)} />
<span>{
item.title}</span>
<button onClick={
this.delItem.bind(this, item)}>x</button>
</div>)}
<h3>已经完成{
this.state.list.filter(item => item.done).length}</h3>
{
this.state.list.filter(item => item.done).map(item => <div className='item' key={
item.title}>
<input type="checkbox" checked={
item.done} onChange={
this.checkItem.bind(this, item)} />
<span>{
item.title}</span>
<button onClick={
this.delItem.bind(this, item)}>x</button>
</div>)}
</div>
);
}
}
export default App;