最近需要写一个评论区功能,所以打算仿照抖音做一个评论功能,支持展开和收起,
首先我们需要对功能做一个拆解,评论区功能,两个模块,一个是发表评论模块,一个是评论展示区。接下来对这两个模块进行详细描述。
使用到的技术 uniapp uview2.0 文章最后我会贴上全部源码
这个模块使用uview的两个组件来完成分别是u-popup弹出层和u-input输入框
下面是代码和展示图:
发布
这部分需要注意两点
1.input组件的focus属性的设置:
在弹出层弹出的时候 在open事件中对input的focus属性布尔值设置为true,close时候设置focus为false。这样做的目的是在弹出输入评论的弹窗时会拉起小键盘,这个交互方式是模仿的微信朋友圈发布评论的形式。
2.input的cursorSpacing属性(输入框聚焦时底部与键盘的距离)设置:
当键盘拉起时候整个输入框因为设置了cursorSpacing="30",故整体页面会被小键盘托起。 当收起小键盘时候,输入框有回归到手机底部,因为我们popup设置的是底部的弹出层。这样是和微信朋友圈发布评论是对标的。
这一部分我封装成了组件,因为需求的要求需要下拉加载评论故在组件外部循环一级评论,组件内部展示一级评论和二级评论,其中二级评论是在组件内部去循环,
循环一级评论的时候需要注意,因为后续要获取pinglun组件的实例,所以在ref的设置上面起初我按照for循环提供的index来拼的字符串,这也导致后续bug的出现埋下伏笔,所以我后续调整了,选择了id这个唯一值作为组件实例的ref名字,这个很关键!
组件代码:
{{onePageList.levelOneCommentVo.userName}}
作者
{{onePageList.levelOneCommentVo.content}}
{{onePageList.levelOneCommentVo.likeCount}}
{{ $u.timeFrom(new Date(onePageList.levelOneCommentVo.createTime).getTime())}}
{{item.userName}}
作者
回复 {{item.replayLevelTwoCommentUser.userName}}
{{item.content}}
{{item.likeCount}}
{{ $u.timeFrom(new Date(item.createTime).getTime())}}
查看更多回复
收起
感觉唯一的难点在于因为展开收缩使用的过渡动画,大家应该都知道,想使用这个过渡必须设置有效值,也就是说比如我给高度写过渡动画,从一个高度到一个高度,都需要是具体的值,atuo这种被内容撑开的高度是不作数的。
这里拿高度,需要注意的是需要等待渲染完毕再去获取高度,不然拿到的值就是不准确的。
下面是我写的获取高度的函数。如果一个nexttick也获取不到准确高度,那么就再加个延时器,就差不多可以获取到准确高度了。
updatHeight() {
let that = this
this.$nextTick(() => {
// this.timer = setTimeout(() => {
this.createSelectorQuery().select(".pinglunDom").boundingClientRect(function(rect) {
// console.log(rect);
that.pingjiaBoxMaxHeight = rect.height
that.pinglunOpcity = 1
}).exec();
// }, 0)
})
},
还有一个需要注意的点,就是在一级评论发布之后,需要拿到所有pinglu组件的实例去调用这个方法,重置所有二级评论的高度。调用这个方法的前提也必须是一级评论的渲染完毕,不然还是不起作用
以下是代码:
this.$forceUpdate();
this.$nextTick(() => {
for (let i = 0; i < this.onePagePinglunList.length; i++) {
this.$refs[`pinglun-${this.onePagePinglunList[i].levelOneCommentVo.id}`][0].updatHeight()
if (this.onePagePinglunList[i].twoLevelpinglun.length === 0) {
this.$refs[`pinglun-${this.onePagePinglunList[i].levelOneCommentVo.id}`][0].params.current = 1
}
}
})
至此应该就没什么需要注意的地方了
可能也是第一次写这个功能,还有很多可以优化的地方。希望对各位有所帮助,接下来我把评论功能所有源码贴在下面。
因为我的评论功能是在案例详情里面的,所以有两个文件,一个是案例详情,一个就是封装的评论组件
案例详情:
成功蜕变历程
体重
{{topweightcha||0}}kg
逆糖3个月
空腹血糖
{{topxuetangcha||0}}mmol/L
{{detailData.userInfoVo.userName||'暂无昵称'}}
{{detailData.isExistServicePack?detailData.servicePackVo.servicePackName:'暂无服务包'}}
项目
管理前
管理后
服务时间
{{detailData.managementInfoVo.managementStartTime||'--'}}
{{detailData.managementInfoVo.managementEndTime||'--'}}
体重
kg
{{detailData.managementInfoVo.beforeManagementWeight||'--'}}
{{detailData.managementInfoVo.afterManagementWeight||'--'}}
空腹血糖
mmol/L
{{detailData.managementInfoVo.beforeManagementFastingSugarBlood||'--'}}
{{detailData.managementInfoVo.afterManagementFastingSugarBlood||'--'}}
用药数量
{{detailData.managementInfoVo.beforeManagementMedicationCount||'0'}}
{{detailData.managementInfoVo.afterManagementMedicationCount||'0'}}
对比照片
暂无
暂无
健康评价
{{item.content}}
{{detailData.interActionVo.commentCount||'0'}} 评论
- 让每个人都能从知识中获得健康 -
说点什么吧
{{detailData.interActionVo.likeCount||'0'}}
{{detailData.interActionVo.collectionCount||'0'}}
{{detailData.interActionVo.commentCount||'0'}}
发布
pinglun组件:
{{onePageList.levelOneCommentVo.userName}}
作者
{{onePageList.levelOneCommentVo.content}}
{{onePageList.levelOneCommentVo.likeCount}}
{{ $u.timeFrom(new Date(onePageList.levelOneCommentVo.createTime).getTime())}}
{{item.userName}}
作者
回复 {{item.replayLevelTwoCommentUser.userName}}
{{item.content}}
{{item.likeCount}}
{{ $u.timeFrom(new Date(item.createTime).getTime())}}
查看更多回复
收起
案例详情引入的scss文件:
.font-20 {
font-size: 20rpx;
font-weight: 400;
}
.font-24 {
font-size: 24rpx;
font-weight: 400;
}
.txt-1 {
font-size: 28rpx;
font-weight: 500;
color: #0F2C50;
}
.txt-2 {
@extend .font-20;
color: #667286;
}
.txt-3 {
@extend .font-24;
color: #667286;
}
.txt-4 {
font-size: 24rpx;
font-weight: 500;
color: #667286;
}
.txt-5 {
font-size: 36rpx;
font-weight: bold;
}
.txt-6 {
@extend .font-24;
color: #9CADC6;
}
.txt-7 {
@extend .font-20;
color: #B7BCC3;
}
.txt-8 {
@extend .font-24;
color: #fff;
}
.txt-9 {
@extend .font-24;
color: #0F2C50;
}
.txt-10 {
font-size: 28rpx;
font-weight: 400;
color: #667286;
}
.yell-green-base {
width: 140rpx;
height: 52rpx;
border-radius: 2rpx;
font-size: 36rpx;
font-weight: bold;
}
.yellow-box {
@extend .yell-green-base;
background-color: #FFF4CD;
color: #FF991F;
}
.green-box {
@extend .yell-green-base;
background: #E2FFEE;
color: #00875A;
}
.timeFont{
font-size: 32rpx;
font-family: DINAlternate-Bold, DINAlternate;
font-weight: bold;
}
.startTime{
@extend .timeFont;
color: #FF991F;
}
.endTime{
@extend .timeFont;
color: #00875A;
}
.line {
height: 1rpx;
border: 1rpx solid #E6E6E6;
margin: 16rpx 0;
}
.caseBox {
background: #FFFFFF;
border-radius: 12rpx;
margin-top: 20rpx;
padding: 0 32rpx;
.case-head-box {
height: 140rpx;
}
.avatarBox {
width: 72rpx;
height: 72rpx;
margin-right: 16rpx;
}
.caseDetailBtn {
width: 100rpx;
height: 44rpx;
background: #00875A;
border-radius: 22rpx;
}
.rateBox {
height: 80rpx;
}
.mar-80 {
margin-right: 80rpx;
}
}