前言
终于把 氢论坛 的评论系统完成的七七八八了,卡了我很久很久,一直在想怎样才能简洁, 优美地弄出来一个评论系统.然而写着写着发现不知不觉中反而变得愚钝而麻烦了.前前后后花了将近一周时间(期间在写其他模块,闲暇的时候就会想一想关于评论的实现),最后也没有很满意.
但是不管怎么样,功能终归是实现了.其中还有一部分未完成,比如说@某人,以及评论区的 markdown语法解析 .不过这些都不是什么问题了,所以暂且忽略掉这些细枝末节,就当我完成了叭.
此文用来记录下我的设计思路及过程,毕竟是第一次写.权当借鉴啦~
演示
gif
静态图
后端设计
一开始,我想的是评论共分成四级,每一级多一点缩进,这样显示层次. 不过在看了看 bilibili, 掘金, CSDN 等一些网站后发现基本上都是用的二级.就也改成二级的了.父评论作为对文章的评论,如上图的”我来评论一下
“和”在来一下
“.子评论是对评论的回复.如上图无名氏对bestsort的回复.这里我把父评论和子评论单独拆分成了两个表,其主要结构如下:
1 | #父评论 |
1 | #子评论 |
其实起初我是放在一个表里的,但是那样的话把对应文章的评论取出来后还得在后台进行排序,然后在进行归类处理.但是排序本身的时间复杂度就是 $O(nlog(n))$的,而且把评论放在一个表里的话子评论会占据大量无用空间,如果想要加速就得依靠索引.但是添加联合索引其实没有太大必要,而且也没有拆开后分别添加索引来的快.想了想(其实就是踩了坑)最终还是把表拆成了上面这样子,然后 以 comment_parent
为驱动表,comment_kid
为被驱动表去查询.因为我用了 mybatis
, 所以可以直接将结果映射成 CommentParent
实体中嵌套List<CommentKid>
的形式. sql查询语句如下(知道最好不用select *,但是我真的懒得写了,目前来说这个不足以影响到性能).
1 | select |
前端
我觉得前端才是我写这个的最大掣肘…因为我是真的不会阿QAQ.
因为父评论涉及到点赞功能,所以要在 HTML 中嵌入每一个评论在数据库中对应的id, 还得根据选择器确定到底选的是哪一条,还得判断是父评论还是子评论. 偏偏我又不想循环去每个评论上都加一个id然后直接用id选择器去选择对应评论…这就导致了大部分时间我都在想怎么捣鼓这里…最后无奈之下,采用了以下方案:
在一个选项点击后,用jQuery去取出它父级/祖父内存着的value(因为无论是父评论还是子评论结构都是固定的.但是这样有个很不好的点就是修改结构后得连这块一起修改,可以说是增加了耦合度吧),然后通过jQuery去修改弹出框的内容.HTML 部分如下:
1 | <li style="margin: 0" value="4"> |
jQuery 相关部分
1 | $(document).on('click',".comment-post>span",function () { |
当然整体肯定不止才这么点,我只是在这里提供一下思路抛砖引玉.想进一步了解的可以去我的仓库查看源码.
其中后端处理部分主要位于CommentService.java
前端处理部分主要位于question-details.js.
氢论坛目前还在搭建中,不介意的话赏个 star 鼓励一下呀~