根据前期所介绍的组件基础,实现一个评论列表的案例,要实现的功能分为四个部分:
- 渲染评论列表(列表渲染)
- 没有评论数据时渲染:暂无评论(条件渲染)
- 获取评论信息,包括评论人和评论内容(受控组件)
- 发表评论,更新评论列表(setState())
初始搭建的页面结构为:
<style>
.app{
margin:20px auto;
border:1px solid #ccc;
width:270px;
height:100%;
padding:10px;
}
.user{
width:260px;
height: 15px;
}
.content{
width:260px;
margin-top:10px;
}
</style>
<body>
<div id="root"></div>
<script type="text/babel">
let root = document.getElementById('root')
class App extends React.Component{
render(){
return (
<div className='app'>
<div >
<input className='user' type="text" placeholder='请输入评论人'/>
<br />
<textarea className="content" cols="30" rows="10" placeholder='请输入评论内容'></textarea>
<br />
<button>发表评论</button>
</div>
<div className='no-comment'>暂无评论,快去评论吧!</div>
<ul>
<li>
<h3>评论人:王欢</h3>
<p>评论内容:前端!!!</p>
</li>
</ul>
</div>
)
}
}
//元素渲染
ReactDOM.render(<App />,root)
</script>
</body>
实现效果为:
接下来,就来一一实现其功能。如下所示:
1. 渲染评论列表
① 在 state 中初始化评论列表数据
② 使用数组的map方法遍历state中的列表数据
③ 给每个被遍历的li元素添加key属性
如下所示:
//初始化状态
state = {
comments:[
{id:1,name:'小欢',content:'好好学习!'},
{id:1,name:'小熊',content:'天天向上!'},
{id:1,name:'小冉',content:'大佬出场!'}
]
}
<ul>
{
this.state.comments.map(item=>(
<li key={item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
</li>
))
}
</ul>
实现效果为:
2. 渲染暂无评论
① 判断列表数据的长度是否为0
② 如果为0,则渲染暂无评论
如下:
{/* 渲染评论列表 */}
{ this.state.comments.length ===0
? ( <div className='no-comment'>暂无评论,快去评论吧!</div>)
:(<ul>
{this.state.comments.map(item=>(
<li key={item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
</li>
))}
</ul>)}
当将state里面的内容注释掉,可以得到:
3. 获取评论信息
① 使用受控组件方式处理表单元素
如下所示:
在state里面定义input和textarea输入的初始值,并获取输入的值,
state = {
comments:[
//{id:1,name:'小欢',content:'好好学习!'},
// {id:1,name:'小熊',content:'天天向上!'},
//{id:1,name:'小冉',content:'大佬出场!'}
],
username:'',
userContent:''
}
handleForm=(e)=>{
const {name,value}=e.target
this.setState({
[name]:value
})
}
<input className='user' type="text" placeholder='请输入评论人'value={this.state.userName} name='userName' onChange={this.handleForm}/>
<br />
<textarea className="content" cols="30" rows="10" placeholder='请输入评论内容' value={this.state.userContent } name='userContent' onChange={this.handleForm}></textarea>
实现效果为:
4. 发表评论
① 给按钮绑定单击事件
② 在事件处理程序中,通过state获取评论信息
③ 将评论信息添加到state中,并调用 setState() 方法更新state
如下所示:
add=()=>{
const {comments,userName,userContent} = this.state
const newComments = [{id:Math.random(),name:userName,content:userContent},...comments]
this.setState({
comments:newComments
})
}
<button onClick={this.add}>发表评论</button>
此时的实现效果为:
基本实现。但是我们发现这样并不美观,当我们内容发表完成后,文本框的内容并没有清空,而且不输入任何内容也可以发布。所以,我们接下来还要进行边界判断:
④ 边界情况:清空文本框
⑤ 边界情况:非空判断
如下所示:
如果输入内容为空,则弹出警示框,提示:请输入内容;且当输入内容发布完成后,文本框的内容清空。
//清除文本框的值即将state清空
this.setState({
comments:newComments,
userName:'',
userContent:''
})
add=()=>{
const {comments,userName,userContent} = this.state
//非空校验
if(userName.trim()==='' || userContent.trim()===''){
alert('请输入内容')
return
}
const newComments = [{id:Math.random(),name:userName,content:userContent},...comments]
this.setState({
comments:newComments,
userName:'',
userContent:''
})
}
实现效果为:
完整代码为:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../react的js库/react.development.js"></script>
<script src="../react的js库/react-dom.development.js"></script>
<script src="../react的js库/babel.min.js"></script>
<style>
.app{
margin:20px auto;
border:1px solid #ccc;
width:270px;
height:100%;
padding:10px;
}
.user{
width:260px;
height: 15px;
}
.content{
width:260px;
margin-top:10px;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
let root = document.getElementById('root')
class App extends React.Component{
//初始化状态
state = {
comments:[
// {id:1,name:'小欢',content:'好好学习!'},
// {id:2,name:'小熊',content:'天天向上!'},
// {id:3,name:'小冉',content:'大佬出场!'}
],
userName:'',
userContent:''
}
handleForm=(e)=>{
const {name,value}=e.target
this.setState({
[name]:value
})
}
add=()=>{
const {comments,userName,userContent} = this.state
//非空校验
if(userName.trim()==='' || userContent.trim()===''){
alert('请输入内容')
return
}
const newComments = [{id:Math.random(),name:userName,content:userContent},...comments]
this.setState({
comments:newComments,
userName:'',
userContent:''
})
}
render(){
return (
<div className='app'>
<div >
<input className='user' type="text" placeholder='请输入评论人'value={this.state.userName} name='userName' onChange={this.handleForm}/>
<br />
<textarea className="content" cols="30" rows="10" placeholder='请输入评论内容' value={this.state.userContent } name='userContent' onChange={this.handleForm}></textarea>
<br />
<button onClick={this.add}>发表评论</button>
</div>
{/* 渲染评论列表 */}
{ this.state.comments.length ===0
? ( <div className='no-comment'>暂无评论,快去评论吧!</div>)
:(<ul>
{this.state.comments.map(item=>(
<li key={item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
</li>
))}
</ul>)}
</div>
)
}
}
//元素渲染
ReactDOM.render(<App />,root)
</script>
</body>
</html>