【Strelitzia项目】评论区的实现

简介

实现Strelitzia项目中的评论区功能,最近想要实现中项目中评论区2层分级的评论区效果。效果图如下,但是不知道该如何去找相关的攻略。经过搜索参看的是这篇文章https://blog.csdn.net/wwb44444/article/details/127728314,非常感谢这篇文章给了很大的思路。话不多说,现在开始讲解我是如何实现的。
在这里插入图片描述

数据库表的设计

想要实现二级评论,那么就需要父评论和子评论存在一个对应的关系,这就不难想到,直接在评论表中加上一个id,指向父评论的id不就好了么。另外还需要相当一件商品会存在多个父评论,所以看表的结构。
在这里插入图片描述
这两个字段是必须要存在的,其余的参数可以暂时先不用管。在这里还有一个小细节,那就是对根父评论做出一个约定,当值为0时,则表示他就是一级评论,非0时,则为二级评论。

后端代码实现

先看pojo类是什么样子的
在这里插入图片描述
这里有几个参数都是传递给前端的,首先不用看sid、suerid这四个,直接看最下面的children集合,这个集合的目的就是将属于这条评论下的二级评论全部的放进去。所以也就是对这个集合的处理是最为重要的。看下面对二级评论的处理方法。

public static List<StrelitziaComment> processStrelitziaComments(List<StrelitziaComment> list) {
        Map<Long, StrelitziaComment> map = new HashMap<>();
        List<StrelitziaComment> result = new ArrayList<>();
        // 将所有根评论加入 map
        for(StrelitziaComment StrelitziaComment : list) {
            if(StrelitziaComment.getRootParentId() == null)
                result.add(StrelitziaComment);
            map.put(StrelitziaComment.getId(), StrelitziaComment);
        }
        // 子评论加入到父评论的 child 中
        for(StrelitziaComment StrelitziaComment : list) {
            Long id = StrelitziaComment.getRootParentId();
            if(id != null) {   // 当前评论为子评论
                StrelitziaComment p = map.get(id);
                // 存放二级评论
                if(p.getChildren() == null)
                    p.setChildren(new ArrayList<>());
                p.getChildren().add(StrelitziaComment);
            }
        }
        return result;
    }

代码中的注解已经非常的详细了,接下来就是接口的调用,注意两点,一个就是不能查询被删除的评论,第二点就是要查询对应商品的评论(不过我这里没有做分页展示,后续再补充上)。额外补充一点,就是由于我的雪花算法会导致id过长,前端接受lang型的数据接受不到,所以需要将其转换为string类型的数据。

@Operation(summary = "商品列表")
    @RequestMapping(value = "/list2",method = RequestMethod.POST)
    public AjaxResult list2(@RequestBody String requestData, HttpServletRequest request) throws ParseException {
        log.info("comment list2 start");
        LambdaQueryWrapper<StrelitziaComment> queryWrapper = new LambdaQueryWrapper<>();
        JSONObject requestJson = JSONObject.parseObject(requestData);
        Long goodsId = requestJson.getLong("goodsId");
        queryWrapper.eq(StrelitziaComment::getGoodsId,goodsId);
        queryWrapper.eq(StrelitziaComment::getDelFlag,0);
        List<StrelitziaComment> list = commentService.list(queryWrapper);
        for (StrelitziaComment strelitziaComment : list) {
            strelitziaComment.setSid(String.valueOf(strelitziaComment.getId()));
            strelitziaComment.setSUserId(String.valueOf(strelitziaComment.getUserId()));
            strelitziaComment.setSGoodsId(String.valueOf(strelitziaComment.getGoodsId()));
            strelitziaComment.setSRootParentId(String.valueOf(strelitziaComment.getRootParentId()));
        }
        List<StrelitziaComment> result = processStrelitziaComments(list);
        AjaxResult ajaxResult = new AjaxResult();
        ajaxResult.put("data",result);
        ajaxResult.put("dataSize",result.size());
        ajaxResult.put("code",200);
        log.info("comment list2 end");
        return ajaxResult;
    }

这里展示一下数据的样子,好吧,由于数据量过大,所以暂时展示就这么点数据,大致是这样子的理解就好。

"data": [
        {
            "id": 1,
            "createTime": "2023-11-04T15:23:25.000+00:00",
            "updateTime": null,
            "replyTo": "0",
            "goodsId": 7125015228491759616,
            "userId": 1,
            "content": "这是我最喜欢的礼物!",
            "delFlag": 0,
            "rootParentId": null,
            "children": [
                {
                    "id": 2,
                    "createTime": "2023-11-04T15:25:05.000+00:00",
                    "updateTime": null,
                    "replyTo": "1",
                    "goodsId": 7125015228491759616,
                    "userId": 1,
                    "content": "这是第二次尝试评论",
                    "delFlag": 0,
                    "rootParentId": 1,
                    "children": null,
                    "sgoodsId": "7125015228491759616",
                    "srootParentId": "1",
                    "suserId": "1",
                    "sid": "2"
                },
                {
                    "id": 7138438729705717760,
                    "createTime": "2023-12-07T08:06:58.000+00:00",
                    "updateTime": "2023-12-07T08:06:58.000+00:00",
                    "replyTo": "1",
                    "goodsId": 7125015228491759616,
                    "userId": 1,
                    "content": "这是第三次评论",
                    "delFlag": 0,
                    "rootParentId": 1,
                    "children": null,
                    "sgoodsId": "7125015228491759616",
                    "srootParentId": "1",
                    "suserId": "1",
                    "sid": "7138438729705717760"
                },
                {
                    "id": 7138438766913388544,
                    "createTime": "2023-12-07T08:07:07.000+00:00",
                    "updateTime": "2023-12-07T08:07:07.000+00:00",
                    "replyTo": "1",
                    "goodsId": 7125015228491759616,
                    "userId": 1,
                    "content": "这是第四次评论",
                    "delFlag": 0,
                    "rootParentId": 1,
                    "children": null,
                    "sgoodsId": "7125015228491759616",
                    "srootParentId": "1",
                    "suserId": "1",
                    "sid": "7138438766913388544"
                },

至此,后端的代码就已经写完了,现在终于到了最最最令人折磨的前端代码环节,需要把这些数据展示出来,并且展示成我想要的样子,无疑是一种巨大的挑战。所以从这里开始,才是最真正的地狱难度。

前端vue3+setup+vite+ts模式

前端拿到后端的数据首先第一件事情就是明确该如何构思一下商品如何展示,由于我定义的是二级评论,那么我觉得大概的样子就是这样的。
在这里插入图片描述
那么首先就想到了两层for循环,第一层for循环用于展示一级评论,若一级评论中存在二级评论,那么就for循环展示二级评论。首先对接受数据的对象进行一个定义

// 评论数组对象
let commentList = reactive({
    total: 0,
    comment: reactive([{
        sid: '',
        id: '',
        createTime: '',
        updateTime: '',
        replyTo: '',
        content: '',
        suserId: '',
        sgoodsId: '',
        photo: '',
        nickName: '',
        rootParentId: '',
        children: reactive([{
            sid: '',
            id: '',
            createTime: '',
            updateTime: '',
            replyTo: '',
            content: '',
            suserId: '',
            sgoodsId: '',
            photo: '',
            nickName: '',
            rootParentId: '',
            replyName: '',
        }]),
    }])
})

接收数据的方式在于

onBeforeMount(async () => {
    isEdit = store.state.goods.isEdit
    await getCommentById(store.state.goods.goodsId)
})

对上述的代码中的isEdit变量我们后续再讨论,首先是确定好了getCommentById,那么接下来就需要考虑一个点,如果是每个一级评论下面都有10个二级评论,并且都展示了出来,那情况就像是这样显得非常的臃肿。
在这里插入图片描述
参考了知乎网站的评论区,都是存在一个点击展开的选项,那么把获取到的二级评论只展示两条,还需要一个对一级评论下二级评论超过两条的数据设置一个“点击展开”的按钮。html代码如下

<div class="commentBox" v-for="item in commentList.comment" :key="item.id">
....中间展示一级评论的相关信息
<div v-for="child in item.children">
....中间展示二级评论的相关信息
</div>
....这里是点击展开按钮
<div v-if="needOpenButton.includes(item.sid)" class="openCommentButton">
<a @click="showMoreSign(item.sid)" class="openButton">{{ byClickIndex === item.sid ? '点击收起' : '点击展开'
}}</a>
</div>
</div>

然后去设置每次显示两条二级评论,并且判断是否存在点击展开的按钮。关键代码如下:

let i: number = 0
while (i < commentList.comment.length) {
   await getUserPhoto(commentList.comment[i], i)
   if (commentList.comment[i].children != null) {
       if (commentList.comment[i].sid !== showMoreIndex) {
           // 将2号位置后的数据全部划掉
           if (commentList.comment[i].children.length > 2) {
               commentList.comment[i].children.splice(2)
               if (needOpenButton === '') {
                   needOpenButton = commentList.comment[i].sid
               } else {
                   needOpenButton = needOpenButton + "," + commentList.comment[i].sid
               }
           }
       }
       for (let j = 0; j < commentList.comment[i].children.length; j++) {
           await getUserPhoto(commentList.comment[i].children[j], j)
       }
   }
   i++
}

其中needOpenButton是需要展开按钮的id拼接字符串,在v-for加载组件的时候,对该按钮id组件进行一个的判断,若当前的id未被needOpenButton包含,那么就不会加载“点击展开”的按钮组件。至此对整个页面的评论区代码就到此结束了。此次主要修改的代码部分位于goodsController以及commentController和userController。前端调整页面,和如何展示数据花费了我很大的时间。还是值得的。

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值