React实现Todolist

react


一个todolist基本的功能点包括:

  1. 点击复选框标记完成或者未完成,且相应的文字出现删除线
  2. 从列表中移除item
  3. 添加item

首先它是由todolist title 、todolist、和addtodo三部分组成。由于todolist title 和addtodo比较简单,在这里只将todolist拆分成组件。

创建一个ListItem组件。含有一个render方法

class ListItem extends Component {

render() {

return (

<ul>

{

this.props.data.map(element => {

return (

<li className="listItem" key={element.name}>

<input type="checkbox"/>

<span>{element.name}</span>

<button className="delete">删除</button>

</li>

)

})

}

</ul>

)

}

}

export default ListItem

this.props.data是父组件传下来的一个list。遍历该list的每一项渲染出来。(注:上面代码体现了 JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。)

此时一个todo的list组件就封装好了,export default出去,让需要的去组件使用。

在父组件TodoList中使用该ListItem组件。

import ListItem from './ListItem'

class TodoList extends Component {

render() {

return (

<div className="reactTodoList">

<header className="header">React todo list</header>

<ListItem data={this.state.list} />

<footer>

<input type="text" placeholder="添加todo"></input>

<button className="addTodo" >添加</button>

</footer>

</div>

)

}

}

ReactDOM.render( <TodoList />, document.getElementById('root'))

由上基本的框架已经搭建出来了,接下来就是list中需要填充数据。

在ListItem组件中有一个接受到的this.props.data的数组,其来自于父组件上的<ListItem data={this.state.list} />。父组件中的state需要声明一下:

constructor() {

super()

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

}]

}

}

在render函数上插入这一段代码,添加一个类构造函数来初始化状态 this.state。React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

接下来父组件通过<ListItem data={this.state.list} />将其list传入到了子组件,子组件中使用map进行渲染。至此页面渲染结束。

1. complete todo

现在要添加交互了。首先实现勾选checkbox出现✅,并且对应的文字出现删除线。注意父组件传入的data的数组中status表示该todo是否完成,所以status就是一个重要的信息。0表示未完成,点击checkbox后,status变为1,表示完成,且文字出现删除线。

<li className="listItem" key={element.name}>

<input type="checkbox"

checked={element.status === 1}

onChange={this.completeTask.bind(this, element.name)}/>

<span style={{textDecorationLine: element.status === 0 ? 'none' : 'line-through'}}>{element.name}</span>

<button className="delete">删除</button>

</li>

这段代码来自于ListItem的组件(可以向上找),现在我们添加在input元素上一个checked属性,和一个onChange事件。

checked表示当status为1时表示完成,当checkbox发生变化的时候就要去更新父组件中的this.status.list相应的status。所以需要一个触发事件completeTask。将此item的name传给父组件,父组件根据name查找到相应的listItem,更新其status。(子组件需要向父组件传值使用函数)。此时在该子组件中定义一个completeTask函数(在render函数上方)。

completeTask(name) {

this.props.completeTask(name)

}

学过vue的应该知道,这有点像vue的子组件emit事件到父组件,父组件通过该事件来进行局部处理。

 <span style={{textDecorationLine: element.status === 0 ? 'none' : 'line-through'}}>{element.name}</span>

在上面这段代码中,通过判断: element.status来添加style,是否出现删除线。

在父组件中应该这样:

<ListItem data={this.state.list} completeTask={this.completeTask1.bind(this)}/>

此段代码来自于父组件TodoList中(向上查找)。代码中的completeTask函数来自于子组件中,completeTask1是需要在父组件中进行处理的父组件函数。这个completeTask1需要完成的事情就是根据子组件传上来的name值,在this.state.list中找到之后更新它的status。若为1更新为0,反之亦然。

completeTask1(name) {

const TodoList = []

this.state.list.forEach((element, index) => {

if (element.name === name) {

const item = this.state.list[index]

TodoList.push(Object.assign({}, item, {status: item.status === 0 ? 1 : 0}))

this.setState({

list: TodoList

})

} else {

TodoList.push(element)

}

})

}

父组件中中的completeTask1函数,遍历this.state.list根据name查找到对应的item,通过Object.assign({}, item, {status: item.status === 0 ? 1 : 0}))来更改status。注:state中的所有数据不允许直接更改。

this.setState({

list: TodoList

})

用来更新state中的数据。

至此就实现了点击checkbox复选框出现对号并且相应文字出现删除线。(完成item的功能)

2. delete todo

点击子组件ListItem中的delete按钮,同样通过函数向父组件传递一个name,父组件根据这个name从this.state.list中移除该item。
子组件中

   <button className="delete" onClick={this.deleteTask.bind(this, element.name)}>删除</button>

render函数上方

deleteTask(name) {

this.props.deleteItem(name)

}

父组件中

<ListItem data={this.state.list} deleteItem={this.deleteItem1.bind(this)}

completeTask={this.completeTask.bind(this)}/>

多了一个deleteItem的函数。

deleteItem1函数中通过name查找item,删除

deleteItem1(name) {

const data = this.state.list.filter(element => element.name !== name)

this.setState({

list: data

})

}

此时一个删除todolist的功能也已经完成。接下来就是添加todo了。

3. add todo

添加todo只需要在父组件中进行操作。

首先需要获得文本框中的输入内容,接下来通过点击添加按钮来给this.state.list中push一项就可以实现啦。

<footer>

<input type="text" value={this.state.inputVal} onChange={this.handleChange.bind(this)} placeholder="添加todo"></input>

<button className="addTodo" onClick={this.addTask.bind(this)}>添加</button>

</footer>

该部分就是添加todo的部分啦。首先input绑定了this.state.inputVal, 并且当输入内容变化的时候更新state中的inputVal。

首先

constructor() {

super()

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

}],

inputVal: ''

}

}

注意添加了一个inputval,用来存储输入框中的内容。实现handleChange函数,并更新state.inputVal

handleChange(e) {

this.setState({

inputVal: e.target.value

})

}

实现了输入框的功能,接下来点击addTask的按钮需要实现添加todo的功能。并且添加成功后输入框中的内容为空。即inputVal为空字符串。

addTask() {

if (!this.state.inputVal) return

this.setState({

list: [...this.state.list, {

name: this.state.inputVal,

status: 0

}],

inputVal: ''

})

}

这个函数中若输入为空不执行任何操作(你也可以添加提示)。添加成功后更新list和inpuVal。

至此一个简单的todolist功能就完成啦。

完整代码见: https://github.com/zhangsundf/React-todoList

以上是 React实现Todolist 的全部内容, 来源链接: utcz.com/z/382282.html

回到顶部