在之前的一篇文章里,曾经介绍过本博客的楼中楼评论系统的实现:如何实现一个楼中楼的评论系统,那时候主要是对后端系统和数据库设计的介绍,本篇文章主要是从前端的角度讲解评论系统的实现!
评论系统最主要的两块是发表评论
和评论列表
,同时呢,发表评论成功后,刷新评论列表主要也是有两种方式:
- ajax的方式刷新,直接追加在特定的位置;
- 刷新整个页面,重新获取评论,然后定位到刚才发表的评论的位置;
本小蚊子博客的评论系统,是以ajax的方式获取评论列表,同时在发表评论成功后,也是以异步的方式更新评论列表。
Vue组件的结构是:
Comments.vue
Publish.vue
List.vue
Unit.vue
Publish.vue
1. 如何发表评论 #
用户对文章或者某个评论产生了共鸣,需要留言讨论一番,我们就需要用户能够把自己的评论也添加进去。
评论的类型,细分的话,可以分为3类:
- 直接对文章发表评论,pid与replyid为空;
- 对一级评论进行回复,pid与replyid均为一级评论的id;
- 对楼中楼进行回复,pid为一级评论的id,replyid为你回复的评论的id
我这里前端的实现参考了oschina(开源中国)的评论方式。直接对文章评论,是直接在顶部的评论窗口进行输入;对其他评论进行回复时,采用弹窗的方式来进行回复。弹窗回复的好处就是,页面不用滚动,用户对某个评论的感知也能停留在这个位置;同时也不用增加各种不必要的小输入框来让用户。
所有发表评论用到的组件都是同一个(Publish.vue),只不过表现的方式不一样而已。在发表评论成功后,通过事件通知机制$emit
,更新数据结构list数组。
当直接对文章评论时,使用splice操作list数组即可:
this.list.splice(0, 0, item); // 在list数组的最前面添加评论内容
当进行楼中楼的评论时,其实是在item中的reply字段里,我们要先更新reply字段,然后再将item重新更新到list数组中:
let item = this.list[index];
item.reply.push(replyItem);
this.$set(this.list, index, item);
// 或
// this.list.splice(index, 1, item);
在更新楼中楼的评论过程中,之前遇到了一个问题:当出现楼中楼的第一个评论时,数据更新但是页面没有更新,从第2个评论开始就能正常更新评论了!刚开始以为是Vue的字段更新后,导致调用的子组件里的数据不会更新。好一通排查后才发现原因竟然是:楼中楼是否显示使用item.num
字段(当前评论里子评论的个数),上面的代码里只是更新了item.reply字段,但是没有更新item.num,导致第一个评论的自动更新老是有问题!
2. 登录的问题 #
之前博客的评论系统,接入的微博登录;一段运行时间后,运行得倒是也没有问题,不过接入微博登录有点大材小用了,最新的评论系统更新时,改为了用户输入昵称和邮箱后即可评论!
用户发表评论后,即将用户的昵称和邮箱存储到cookie中,下次直接从cookie里后去即可!
3. 获取评论列表 #
在获取评论列表时,也是监听了页面的滚动事件,同时采用防抖和节流的策略,在用户将页面滚动到底部的时候再获取数据!在获取到数据后,即解绑滚动事件
handleScroller() {
const scroller = throttle(()=>{
const maxScrollTop = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight) - window.innerHeight;
const currentScrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
if (maxScrollTop - currentScrollTop < 100 && !this.loaded) {
this.loaded = true;
this.getList(); // 获取数据
window.removeEventListener('scroll', scroller);
}
}, 300, 400);
scroller();
window.addEventListener('scroll', scroller);
}
4. 总结 #
评论系统是一项比较复杂的系统,我们这里也只是做了简单的工作而已,后续可能也会考虑,全部使用原生的js来实现!