React实现Todolist
一个todolist基本的功能点包括:
- 点击复选框标记完成或者未完成,且相应的文字出现删除线
- 从列表中移除item
- 添加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