Vue 评论组件设计 V1.0
简介
基于 Element Plus 封装的一套二级评论组件。
算是 Comment V1.0
版本吧,总体还是有很多不完善的地方,后续在安排改进。先用着先吧,哈哈。
本文不算是教学,只是记录设计该组件的思路,虽然只是简单的记录了一下过程,给自己看的,各位仅供参考。
组件演示
Basic / 一级评论
二级评论
点击回复按钮
二级评论默认不展示,只显示回复条目
查看二级评论列表
二级评论回复
查看评论数量
展开评论回复列表
组件分类
CommentEdit
CommentEdit
组件:编辑和发布评论。
对于该组件就不多说什么了,直接用 Element Plus 组件库的表单组件套上直接用就行。
Comment
Comment
组件:作为评论内容的载体,渲染评论。
组件的使用方式
<script setup>
import { ref, onMounted, watch, defineAsyncComponent } from 'vue'
...
import { getRootArticleCommentList } from '@/api/comment'
const commentData = ref()
...
const refreshComment = () => {getRootArticleCommentList(articleId).then((resp) => {if(resp.code === 1)commentData.value = resp.data})
}
...
</script><template><div class="content">...<!-- 评论列表 --><div class="comment-list"><!-- 一级评论,将评论信息 item 通过 data 传递给组件内部,以便渲染和获取二级评论 --><comment :data="item" v-for="item in commentData" :refresh-comment="refreshComment"><!-- 内嵌二级评论,二级评论的数据由一级评论 comment 内部控制 --><template #review-list="{ reviewList }"><comment :review="true" :data="child" v-for="child in reviewList" :refresh-comment="refreshComment"></comment></template></comment></div></div>
</template>
...
commentData
似乎通过 getRootArticleCommentList
API 得到的相应数据,它仅请求一级评论,不请求二级评论。格式如下:
"data": [{"id": 103,"nickname": "哈哈哈","website": "web","avatarHash": "1643ec4b1d1ccee82772f1c7043a27db","createTime": 1756814289000,"beforeTime": "星期二","content": "<span>你好啊!</span><br>",..."reviewTotal": 2}
]
Comment
HTML
<template><div class="comment"><div class="main"><!-- 头像 --><div><img :src="`https://cravatar.com/avatar/${ data.avatarHash }`" alt=""></div><!-- 内容主体 --><div class="box"><!-- 当前评论是二级评论 --><p v-if="review"><span class="name" v-if="data.website == null">{{ data.nickname }}</span><a :href="'https://' + data.website" target="_blank" class="name" v-else>{{ data.nickname }}</a><strong>回复</strong><span class="name">{{ data.toNickname }}</span>·<span class="time">{{ data.beforeTime }}</span><el-tag type="success" size="small" v-if="data.isTitle">{{ data.title }}</el-tag></p><!-- 当前评论不是二级评论,是一级评论 --><p v-else><span class="name" v-if="data.website == null">{{ data.nickname }}</span><a :href="'https://' + data.website" target="_blank" class="name" v-else>{{ data.nickname }}</a>·<span class="time">{{ data.beforeTime }}</span><el-tag type="success" size="small" v-if="data.isTitle">{{ data.title }}</el-tag></p><!-- 评论内容 --><div class="content" v-html="data.content"></div><!-- [回复] 按钮 --><span class="review" @click="enabledReview">回复</span><!-- 如果当前评论不是二级评论,且一级评论下有回复(即存在二级评论) --><span class="review" v-if="!review && data.reviewTotal > 0" @click="setReviewListVisabled">展开 {{ data.reviewTotal }} 条回复</span><!-- 评论发布与回复 --><comment-editv-if="commentEditVisabled".../></div></div><!-- 二级评论列表 --><div class="review-list" v-if="reviewListVisabled" v-loading="loadingFlag"><slot name="review-list" :review-list="reviewList"></slot><div class="close-review-list" @click="reviewListVisabled = false">关闭回复列表</div></div></div>
</template>
先来看看 comment 组件在外部使用时的模样:
...<!-- 一级评论,将评论信息 item 通过 data 传递给组件内部,以便渲染和获取二级评论 --><comment :data="item" v-for="item in commentData" :refresh-comment="refreshComment"><!-- 内嵌二级评论,二级评论的数据由一级评论 comment 内部控制 --><template #review-list="{ reviewList }"><comment :review="true" :data="child" v-for="child in reviewList" :refresh-comment="refreshComment"></comment></template></comment>
...
在 comment 子组件内部通过 prop.data
得到的数据其中的 commentId
去查询得到当前评论下的二级评论列表 reviewList
。然后通过 <slot>
插槽将 reviewList
传递给父组件,父组件再来进行渲染。
js
import { ref } from 'vue'
import CommentEdit from '../CommentEdit/CommentEdit.vue'import { getReviewArticleCommentList, ... } from '@/api/comment'const props = defineProps({review: { Type: Boolean }, // true 代表当前评论是二级评论,false 代表当前评论是一级评论data: { Type: Object }, // 评论具体信息,包括头像、评论时间、昵称、评论内容等信息refreshComment: { Type: Function } // 通过这个函数可以刷新评论
})const commentEditVisabled = ref(false) // true 时将显示 comment-edit 组件
const enabledReview = () => {commentEditVisabled.value = !commentEditVisabled.value
}const reviewList = ref() // 当前评论下的二级评论列表
const loadingFlag = ref(true)
const reviewListVisabled = ref(false) // 是否显示二级评论列表const setReviewListVisabled = () => {loadingFlag.value = truereviewListVisabled.value = trueif(props.data.articleId) {// 获取当前评论回复列表getReviewArticleCommentList(props.data.articleId, props.data.id).then((resp) => {if(resp.code === 1)reviewList.value = resp.dataloadingFlag.value = false})} else {...}
}// 刷新评论的回调
const refreshCommentCallback = () => {props.refreshComment()
}
或许可以看看我的博文:https://fanjuanddz.com/article/37