前言
这一节内容比较多,主要工作集中在这个样式和结构的编写。评论一层,子评论又需要写一层,还有评论过多时的一个折叠展示。
项目地址:https://github.com/cctyl/sunofbeach_mobile.git
结构分析
下面的几个布局都采用的是flex布局,要么是 上下结构,要么是左右结构,互相嵌套就得到了效果
外层结构:
评论详情:
评论的右边:
子评论的分析:
子评论和父评论结构基本一致,但是尺寸小了一些
点击查看更多之后:
点击收起则收回原来状态。
数据
接口地址是:
/ct/article/comment/${articleId}/${page}
还是直接调用接口,返回数据。
但是这里我们要对数据进行一定的处理。
-
时间的处理。
返回的数据中时间格式是 2017-xx-xx 18:11 这个格式,我想要的是 距离现在多久了
用到一个库,moment
npm install moment
安装之后,到main.js引入,然后配置语言
//全局设置语言环境 import moment from "moment"; moment.locale('zh-cn');
到页面中导入使用
import moment from 'moment' //写一个方法方便调用 /** * 计算距离现在有多长时间 */ calcTime(timeStr) { return moment(timeStr, "YYYY-MM-DD HH:mm").fromNow() }
当我们请求完数据之后,就遍历,得到时间,格式化后重新赋值:
//对时间进行一下处理 let commentList = commentResult.data.content.map(item => { item.publishTime = this.calcTime(item.publishTime) //子评论里面的时间也要格式化 if (item.subComments){ for (let i = 0; i <item.subComments.length ; i++) { item.subComments[i].publishTime = this.calcTime(item.subComments[i].publishTime) } } return item })
-
是否展开子评论的标记
页面中我是这么定义的:如果子评论数量大于1,并且它身上的showMore标识为false,那就只展示一条子评论,否则展示全部子评论。所以拿到数据的时候,就需要对所有评论遍历,添加一个标记 showMore
/** * 获取评论数据 */ async getCommentList() { let commentResult = await api.getArticleComment(this.id, this.commentPage) //对时间进行一下处理 let commentList = commentResult.data.content.map(item => { item.publishTime = this.calcTime(item.publishTime) item.showMore =false if (item.subComments){ for (let i = 0; i <item.subComments.length ; i++) { item.subComments[i].publishTime = this.calcTime(item.subComments[i].publishTime) } } return item }) this.commentList = commentList },
-
然后就是到页面中for循环遍历了,具体结构如下:
<!--文章评论-->
<div class="review">
<div class="reviewHeader">
<span>评论({{commentList.length}})</span>
<span class="iconfont icon-edit">写评论</span>
</div>
<!--评论列表-->
<div class="reviewList" >
<div class="reviewItem" v-for="item in commentList" :key="item._id">
<!--评论人头像-->
<div class="left">
<img :src="item.avatar">
</div>
<div class="reviewRight">
<!--评论人信息,点赞-->
<div class="top">
<span class="reviewNikename">{{item.nickname}}</span>
<span >{{item.publishTime}}</span>
</div>
<!--评论内容-->
<div class="reviewBottom">{{item.commentContent}}</div>
<!--下面的子评论-->
<!--太长就不显示这么多-->
<div v-if="item.subComments.length>1 && !item.showMore">
<div class="subcomment">
<!--评论人头像-->
<div class="subleft">
<img :src="item.subComments[0].yourAvatar">
</div>
<div class="subreviewRight">
<!--评论人信息,点赞-->
<div class="subtop">
<span class="subreviewNikename">{{item.subComments[0].yourNickname}}</span>
<span >{{item.subComments[0].publishTime}}</span>
</div>
<!--评论内容-->
<p class="subreviewBottom">
{{item.subComments[0].beNickname? '回复 '+item.subComments[0].beNickname+':':'' }}
{{item.subComments[0].content}}
</p>
</div>
</div>
<!--这里直接就给当前评论加上一个showMore属性,用来标记是否展示更多评论-->
<span class="sub-see-more" @click="item.showMore=true">点击查看更多({{item.subComments.length-1}})</span>
</div>
<div v-else>
<div class="subcomment" v-for="subitem in item.subComments" :key="subitem._id">
<!--评论人头像-->
<div class="subleft">
<img :src="subitem.yourAvatar">
</div>
<div class="subreviewRight">
<!--评论人信息,点赞-->
<div class="subtop">
<span class="subreviewNikename">{{subitem.yourNickname}}</span>
<span >{{subitem.publishTime}}</span>
</div>
<!--评论内容-->
<p class="subreviewBottom">
{{subitem.beNickname? '回复 '+subitem.beNickname+':':'' }}
{{subitem.content}}
</p>
</div>
</div>
<!--这里直接就给当前评论加上一个showMore属性,用来标记是否展示更多评论-->
<span class="sub-see-more" @click="item.showMore=false">收起</span>
</div>
</div>
</div>
<div class="reviewItem" v-show="commentList.length==0">
<div class="noComment ">
<i class="iconfont icon-meiyoushuju"></i> 暂无评论~~
</div>
</div>
</div>
</div>
css如下:
/*文章评论*/
.review {
padding: 10px;
}
.reviewHeader {
display: flex;
justify-content: space-between;
font-size: 16px;
margin-bottom: 10px;
}
.reviewHeader :nth-child(2) {
color: #f15731;
}
.reviewItem {
display: flex;
flex-direction: row;
font-size: 15px;
}
.reviewItem .left {
margin-top: 10px;
width: 45px;
}
.reviewItem .left img {
width: 45px;
height: 45px;
border-radius: 50%;
}
.reviewItem .reviewRight {
flex: 1;
display: flex;
flex-direction: column;
margin-left: 10px;
margin-top: 10px;
}
.reviewItem .reviewRight .top {
display: flex;
justify-content: space-between;
}
.reviewItem .reviewRight .reviewBottom{
margin-top: 10px;
line-height: 25px;
}
/*子评论*/
.reviewItem .reviewRight .subcomment{
margin: 15px 0 5px 20px;
display: flex;
font-size: 13px;
}
.subleft img{
width: 25px;
height: 25px;
border-radius: 50%;
}
.subreviewRight{
flex: 1;
margin-left: 5px;
}
.subreviewRight .subtop{
display: flex;
justify-content: space-between;
}
.subreviewRight .subtop .subreviewNikename{
}
.subreviewBottom{
margin-top: 5px;
line-height: 20px;
}
.sub-see-more{
margin-left: 20px;
color: #409eff;
}
.noComment{
margin-top: 20px;
width: 100%;
text-align: center;
}
.noComment i{
font-size: 18px;
}