完结篇:发送摸鱼动态、动态评论以及评论回复的实现
简介
本期是sob_webapp的最后一期,我们将实现摸鱼的发布和评论的回复。
源码地址:https://github.com/cctyl/sunofbeach_mobile
之前已经完成评论输入框,以及输入按钮的界面实现。现在我们要对其功能进行实现。
这里评论分两个部分
- 一、评论摸鱼动态
- 二、回复摸鱼动态评论的评论
评论摸鱼动态
看下效果:
当我们点击回复按钮时,展开评论列表以及输入框。输入内容后直接调用接口就可以啦,是不是非常简单。
点一下就发送,发送完清空输入框,然后弹出一个提示,最后更新摸鱼动态列表。
其实这种更新做法不太优雅,应该是把我们新增的评论自己push到列表中,但是因为我们无法获得评论id,后续会出现问题,所以直接更新了整个列表。
另外,评论按钮上面的数字也要同步更新(上方的截图漏了)
代码如下:
//接口部分
/**
* 评论摸鱼动态
* POST /ct/moyu/comment
* comment: {
momentId: '',
content: ''
}
*/
sendMoyuComment(momentId,content){
return ajax(`/ct/moyu/comment`, {
momentId,
content
}, 'POST')
}
//发送逻辑
/**
* 发表评论
* @param commentStr
*/
async sendMoyuComment(momentItem) {
console.log("当前的评论内容是:")
console.log(momentItem)
let result = await api.sendMoyuComment(momentItem.id, momentItem.commentStr);
if (result.success) {
this.$toast.success('操作成功!');
momentItem.commentStr = ''
//需要更新回复列表
this.getMomentCommontList(momentItem);
} else {
this.$toast.fail('发送失败!' + result.message);
}
},
回复摸鱼动态评论的评论
稍微还是有一点复杂的
效果如下:
逻辑是这样的,我们挪用了文章评论里的组件,偷懒使用弹出层进行评论,点击评论后展开弹出一个弹出层,注意弹出层中包含一个被回复的用户名。点击评论后,关闭弹出层,清空输入框,刷新评论列表。
这里稍微有一点复杂,我们拿一个案例来解释。
这个摸鱼动态的评论的数据结构是:
{
content:"刚刚更新了一下博客...",
commentItemList:[
{
content:"版本差异挺大的....",
subItem:[
{
content:"回复拉大锯 我一直用"
},
{
content:"回复 断点 你没有使用新的库"
}
]
}
]
}
最外层的是一个MoyuMoment 对象,而内层开始就是一级评论对象。一级评论对象中,有两个子评论对象。总共有三层。
回到图上,图上有三个回复按钮,你觉得他们分别回复的是 一级评论对象,还是子评论对象,还是MoyuMoment 对象?
实际上,这三个按钮回复的都是 一级评论对象,“版本差异挺大的”。
也就是说,虽然下面的两个子评论,看起来是回复关系,实际上是平级关系。
现在我们知道了它的层级结构之后,到时候取commentId 时,就千万不要取错了。取错之后,虽然后端依然会返回评论成功,但是实际上还是评论失败的。
代码大概的贴一下:
<!--弹出层-评论框-->
<nut-popup
position="top"
v-model="showCommentPanel"
>
<!--评论填写框-->
<nut-textbox
class="comment-input"
v-model="popCommentStr"
:place-text="commentPlaceText"
:max-num="300"
:txt-area-h="80"
></nut-textbox>
<nut-button
type="light"
@click="submitComment"
block
>
提交
</nut-button>
</nut-popup>
//api
/**
* 回复评论
* @param content
* @param momentId
* @param targetUserId
* @param commentId
* @returns {Promise<unknown>}
*/
sendMoyuSubComment(
content,
momentId,
targetUserId,
commentId
) {
return ajax(`/ct/moyu/sub-comment`, {
content,
momentId,
targetUserId,
commentId
}, 'POST')
},
//data部分新增变量
showCommentPanel:false,//是否展示评论弹窗
popCommentStr:'',//弹出回复框数据绑定
popCommentType:0,//评论类型,是一级评论,还是子评论
popCommentObj:{},//当前将要回复的评论对象
popCommentTargetUserId:0,//将要回复的用户id
commentMomentItem:{},//当前正在被评论的摸鱼动态对象
//摸鱼逻辑:
/**
* 发表评论
* @param commentStr
*/
async sendMoyuComment(momentItem) {
console.log("当前的评论内容是:")
console.log(momentItem)
let result = await api.sendMoyuComment(momentItem.id, momentItem.commentStr);
if (result.success) {
this.$toast.success('操作成功!');
momentItem.commentStr = ''
//需要更新回复列表
this.getMomentCommontList(momentItem);
} else {
this.$toast.fail('发送失败!' + result.message);
}
},
/**
* 展示评论填写框
*/
openCommentPanel(commentObj,type,targetUserId,targetUserName,momentItem){
this.commentPlaceText = '说说你的想法吧'
//清空旧数据
this.popCommentStr = ""
//打开弹出层
this.showCommentPanel = true
this.popCommentTargetUserId = targetUserId
this.commentMomentItem = momentItem
this.popCommentObj = commentObj;
if (!this.isLogin()) {
return
}
/**
* 4 一级评论
*
*/
this.popCommentType = type
this.commentPlaceText=`回复 @${targetUserName}`
},
/**
* 发送摸鱼评论
*/
async sendMoyuComent(){
let result = await api.sendMoyuSubComment(
this.popCommentStr,
this.popCommentObj.momentId,
this.popCommentTargetUserId,
this.popCommentObj.id
)
if (result.code === 10000) {
this.$notify.success(result.message)
//更新评论列表
this.getMomentCommontList(this.commentMomentItem);
} else {
this.$notify.warn(result.message)
}
},
/**
* 提交评论
*/
handlePopSubmit() {
if (this.popCommentType===5){
//偷懒,使用评论的弹出层
this.sendMoyu();
}else {
this.sendMoyuComent();
}
//清空评论框
this.popCommentStr = ''
//关闭弹窗
this.showCommentPanel = false
this.popCommentObj={}
},
发送摸鱼动态
你会发现我是倒过来做的。先做了摸鱼的评论再做了摸鱼的发布
效果图:
由于今天发了很多摸鱼,所以这里没有点提交。
实现逻辑上,我是直接复用了摸鱼评论的pop框,所以代码几乎一致,不同就是在右下角增加了一个触发按钮:
<!--发布摸鱼按钮-->
<div class="moyu-send-btn" @click="openMoyuPanel">
<i class="action-btn iconfont icon-jiahao" ></i>
</div>
.moyu-send-btn{
position: fixed;
right: 7%;
bottom: 5%;
width: 50px;
height: 50px;
z-index: 1000;
cursor: pointer;
}
.moyu-send-btn .action-btn{
font-size: 45px;
color: #fb6064;
}
简单的贴一下js部分:
//api
/**
* 发表动态
* @param content
* @param topicId
* @param images
* @returns {Promise<unknown>}
*/
publishMoyu(
content,
topicId,
images
) {
return ajax(`/ct/moyu`, {
content,
topicId,
images
}, 'POST')
},
//逻辑
/**
* 发表评论
* @param commentStr
*/
async sendMoyuComment(momentItem) {
console.log("当前的评论内容是:")
console.log(momentItem)
let result = await api.sendMoyuComment(momentItem.id, momentItem.commentStr);
if (result.success) {
this.$toast.success('操作成功!');
momentItem.commentStr = ''
//需要更新回复列表
this.getMomentCommontList(momentItem);
} else {
this.$toast.fail('发送失败!' + result.message);
}
},
/**
* 展示评论填写框
*/
openCommentPanel(commentObj,type,targetUserId,targetUserName,momentItem){
this.commentPlaceText = '说说你的想法吧'
//清空旧数据
this.popCommentStr = ""
//打开弹出层
this.showCommentPanel = true
this.popCommentTargetUserId = targetUserId
this.commentMomentItem = momentItem
this.popCommentObj = commentObj;
if (!this.isLogin()) {
return
}
/**
* 4 一级评论
*
*/
this.popCommentType = type
this.commentPlaceText=`回复 @${targetUserName}`
},
/**
* 发送摸鱼评论
*/
async sendMoyuComent(){
let result = await api.sendMoyuSubComment(
this.popCommentStr,
this.popCommentObj.momentId,
this.popCommentTargetUserId,
this.popCommentObj.id
)
if (result.code === 10000) {
this.$notify.success(result.message)
//更新评论列表
this.getMomentCommontList(this.commentMomentItem);
} else {
this.$notify.warn(result.message)
}
},
/**
* 提交评论
*/
handlePopSubmit() {
if (this.popCommentType===5){
//偷懒,使用评论的弹出层
this.sendMoyu();
}else {
this.sendMoyuComent();
}
//清空评论框
this.popCommentStr = ''
//关闭弹窗
this.showCommentPanel = false
this.popCommentObj={}
},
/**
* 弹出摸鱼发布面板
*/
openMoyuPanel() {
this.commentPlaceText = '今日宜摸鱼'
this.popCommentType = 5
//清空旧数据
this.popCommentStr = ""
//打开弹出层
this.showCommentPanel = true
if (!this.isLogin()) {
return
}
},
/**
* 发送摸鱼动态
*/
async sendMoyu(){
let result = await api.publishMoyu(this.popCommentStr ,'',[])
console.log(result)
if (result.code === 10000) {
this.$notify.success(result.message)
//刷新动态列表
this.pulldown();
} else {
this.$notify.warn(result.message)
}
}
打包部署
打包方面,非常的简单,只需要在命令行,输入npm run build
,就会进行打包。生成的文件会放在根目录下的 dist
目录。
接下来就是部署了,这里使用的是nginx进行部署,具体怎么安装nginx就不在本教程内容里了。
我们直接把dist下的所有文件,上传到nginx指定的资源目录下,然后访问网站即可~。
稍微需要注意下,如果刷新后路由丢失,需要修改nginx的配置,我在前几篇文章已经提到过,这里就不多说啦。
结语
这个项目最初从 2021年10月9日创建,到2022年的4月分就暂停了一下,到现在间隔一年重新捡起,然后收尾。
目前完成的功能有:
- 登录
- 首页文章列表
- 文章详情、文章回复
- 摸鱼列表、摸鱼回复
- 话题切换
最初的目的
最初写这个项目的目的,是想着刚刚学习前端,需要一个项目来巩固自己的知识,为后续工作打下基础。事实上这个项目确实给我带来了很多相关的经验。
然后就哼哧哼哧的开始编写,写到1月份,暂停了一下。那段时间工作比较忙了。到了4月份,又出现了空闲,于是又恢复更新。4月底基本就写完了摸鱼页面。然后又是一直拖,到现在总算抽出时间来把这个系列进行完结。
为啥不继续了
实际上,到现在为止,这个sob_webapp只完成了sob主站的20%不到的功能。
但是在去年4月份我就已经实现了最初的目的了,
vue、vuerouter、vuex 等当时也相对熟练了,并且我最常用的几个功能我也写的差不多了,
同时工作比较忙,后续公司团队逐渐壮大,我也不需要兼职前端,精力都花在后端上,前端慢慢的也就荒废了,知识忘记了好多,现在我已经把css的布局知识都忘得差不多了,后续还需要重新复习,技术就是这样,久了不用,就会生疏。最后就渐渐的搁置了。
项目的缺陷
当时写这个项目时我还是个刚入门的菜鸟,啥也不懂。有些地方写的惨不忍睹,有些积重难返的意思。复用性也不好,bug一堆。只能说勉强用一用。好多细节部分是强行实现的哈哈,一点也不优雅,这也是不更新的一部分理由。
另外,当时编写这个项目的时候,vue2还算是主流。而现在,主流都是vue3+typescript,就连vuex vuerouter就更新换代好几个版本,vue-cli也换成了vite,主流ui框架也都适配了vue3。这个项目着实有些落后,不宜作为一个良好的教程了,估计新手也几乎不会看了。属于是旧时代的渣渣。
后续目标
综上所述,这个系列完结了。但是我应该、或许、可能还会基于另一个语言实现一下sob的主站。选择做sob客户端,主要是为了熟悉新技术,但是需要数据源啊,需要后端呀,sob这有现成的后端api,也有真实数据,并且还不需要我维护后端,属于是练习的良选。所以下一门技术,估计还会对sob进行实现。
话就到这里,感谢大家的支持