翻翻以前做的demo,有个博客项目,其中评论系统稍显复杂。今日拿来扯一扯。
效果是二级评论,就是一级评论之下,多层回复在同一楼,以@符号表示上一级。两层嵌套评论都做了分页。每一层评论下都有回复功能,不做过多嵌套,是照顾了美观与实用。
前端是用的比较老的vue2,前后端变量命名有些随意和简洁了。为了实现这种嵌套,数据库评论表中的设计了cu1和cu2两个字段,前者表示一级评论是谁,就在谁的楼层下显示评论,如果该字段为空就表示是blog下的一级评论。而cu2表示一级评论下的二级评论是谁,就是二层中显示的@谁的回复,没有cu3,因为虽是多级但没有三层,有cu2这个字段就够了。
前端的评论组件必须是嵌套组件了,cNum用于标记一级,而在嵌套组件中这个值就不同了,用于样式区分设定。
<comment v-if="item.children" :data="item.children" :id="item.id" :cNum="cNum + 1"/>
下面再说说定位消息功能,效果是登陆用户有未读消息提醒,单击消息上每一条都会定位到相关回复的位置并高亮显示。这在其他评论系统中根本没见过或实现过。就特别想做出功能看看。
因为评论有多页,二层评论也有多页,那必须是自动翻页到一级再翻页到二级层中高亮显示。
1.点击消息提示,向后端传递blogId,cu1Id和消息id三个参数。
2.要检测出消息所在哪一条评论,确定出所在哪一页评论十分重要,就是两层第几页的count值。
3.评论id是自增的,根据这个值就能统计出楼层的第多少个评论,从而确定是第几页。
4.根据回复条目查询一级评论队列中第几个:
select count(id) from comment where blog_id = #{blogId} and cu1_id is null and id>= #{id}
5.根据回复条目查询二级评论队列中第几个:
select count(id) from comment where blog_id = #{blogId} and cu1_id=#{cu1id} and id<= #{id}
6.根据这两个序列号,能确定在第几页,比如一页5条。查出两页数据显示即可。
7.在后端组装数据时,塞入该条id的tip属性,例如m.put("tip",1); 。
8.前端解析出tip设置高亮样式:
<div class="c-c" :class="item.tip?'commentTip':''">{{ item.content }} </div>
9.滚动到消息位置:
document.querySelector('.commentTip').scrollIntoView(true)
这个评论系统也就是前端代码稍显复杂,comment 组件:
<template>
<div v-if="data">
<div
class="comments-o"
:class="[cNum > 0 ? 'ono' : '']"
v-for="(item, index) in contents.data"
:key="index"
>
<div class="c-title">
<el-avatar
size="small"
:src="
item.tx
? item.tx
: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
"
></el-avatar>
<b>{{ item.userName }}</b>
<span v-show="item.cu2Id"
>回复:@<a>{{ item.cu2Name }}</a></span
>
<em>|</em>
<time>{{ item.time | dateFormat }}</time>
</div>
<div class="c-c" :class="item.tip?'commentTip':''">
{{ item.content }}
</div>
<div class="c-g">
<span
@click="
() => {
item.ishf = true;
}
"
>回复</span
>
<span>删除</span>
<span
v-show="item.ishf"
@click="
() => {
item.ishf = false;
}
"
>收起回复</span
>
</div>
<div class="lou">
<el-form
:model="ruleForm"
:rules="rules"
label-width="100px"
class="demo-ruleForm"
v-show="item.ishf"
>
<el-form-item label="" prop="desc">
<el-input type="textarea" v-model="ruleForm.desc"></el-input>
</el-form-item>
<el-form-item class="plbotton">
<el-button
size="mini"
type="primary"
@click="reply(item.id, item.userId)"
>回复</el-button
>
<el-button size="mini" @click="resetForm('ruleForm')"
>重置</el-button
>
</el-form-item>
</el-form>
<comment
v-if="item.children"
:data="item.children"
:id="item.id"
:cNum="cNum + 1"
/>
</div>
</div>
<div class="fyo">
<el-pagination
class="fy"
:page-size="5"
v-show="contents.total > 5"
layout="prev, pager, next"
:total="contents.total"
v-if="cNum < 2"
:current-page.sync="currentPage"
@current-change="currChange"
>
</el-pagination>
</div>
</div>
</template>