|
|
|
|
@ -1,28 +1,36 @@
|
|
|
|
|
<template>
|
|
|
|
|
<!-- 评论项容器,设置外边距和最大宽度 -->
|
|
|
|
|
<div class="mt-5 max-w-full">
|
|
|
|
|
<div class="flex space-x-3 xl:space-x-5">
|
|
|
|
|
<!-- 评论者头像组件,使用评论数据中的头像地址 -->
|
|
|
|
|
<Avatar :url="comment.avatar" />
|
|
|
|
|
<div class="max-w-full-calc space-y-5">
|
|
|
|
|
<!-- 评论内容区域,设置背景、内边距、圆角等样式 -->
|
|
|
|
|
<div class="bg-white text-primary p-4 rounded-md relative shadow-md reply" style="width: fit-content">
|
|
|
|
|
<!-- 评论内容,将换行符替换为<br>标签以正确显示换行 -->
|
|
|
|
|
<p class="commentContent" v-html="comment.commentContent.replaceAll('\n', '<br>')" />
|
|
|
|
|
<!-- 评论元信息区域:评论者昵称、时间和回复按钮 -->
|
|
|
|
|
<div class="flex justify-between mt-3 text-xs text-gray-400 space-x-3 md:space-x-16">
|
|
|
|
|
<span>{{ comment.nickname }} | {{ time }}</span>
|
|
|
|
|
<div>
|
|
|
|
|
<!-- 回复按钮,点击显示回复表单 -->
|
|
|
|
|
<span @click="clickOnReply" class="cursor-pointer reply-button">Reply</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- 回复表单组件,通过v-show控制显示/隐藏 -->
|
|
|
|
|
<CommentReplyForm
|
|
|
|
|
v-show="show"
|
|
|
|
|
:replyUserId="comment.userId"
|
|
|
|
|
:initialContent="replyContent"
|
|
|
|
|
@changeShow="changeShow" />
|
|
|
|
|
v-show="show"
|
|
|
|
|
:replyUserId="comment.userId"
|
|
|
|
|
:initialContent="replyContent"
|
|
|
|
|
@changeShow="changeShow" />
|
|
|
|
|
<!-- 评论的回复列表,使用过渡组实现动画效果 -->
|
|
|
|
|
<transition-group name="fade">
|
|
|
|
|
<CommentReplyItem
|
|
|
|
|
v-for="reply in comment.replyDTOs"
|
|
|
|
|
:key="reply.id"
|
|
|
|
|
:reply="reply"
|
|
|
|
|
:commentUserId="comment.userId" />
|
|
|
|
|
v-for="reply in comment.replyDTOs"
|
|
|
|
|
:key="reply.id"
|
|
|
|
|
:reply="reply"
|
|
|
|
|
:commentUserId="comment.userId" />
|
|
|
|
|
</transition-group>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@ -30,50 +38,68 @@
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
// 导入Vue相关API
|
|
|
|
|
import { defineComponent, reactive, ref, toRefs, provide } from 'vue'
|
|
|
|
|
// 导入头像组件
|
|
|
|
|
import Avatar from '@/components/Avatar.vue'
|
|
|
|
|
// 导入回复项组件
|
|
|
|
|
import CommentReplyItem from './CommentReplyItem.vue'
|
|
|
|
|
// 导入回复表单组件
|
|
|
|
|
import CommentReplyForm from './CommentReplyForm.vue'
|
|
|
|
|
|
|
|
|
|
// 定义评论项组件
|
|
|
|
|
export default defineComponent({
|
|
|
|
|
components: {
|
|
|
|
|
Avatar,
|
|
|
|
|
CommentReplyItem,
|
|
|
|
|
CommentReplyForm
|
|
|
|
|
Avatar, // 注册头像组件
|
|
|
|
|
CommentReplyItem, // 注册回复项组件
|
|
|
|
|
CommentReplyForm // 注册回复表单组件
|
|
|
|
|
},
|
|
|
|
|
props: ['comment', 'index'],
|
|
|
|
|
props: ['comment', 'index'], // 接收父组件传入的评论数据和索引
|
|
|
|
|
setup(props) {
|
|
|
|
|
// 获取评论数据
|
|
|
|
|
const comment: any = props.comment
|
|
|
|
|
// 向子组件提供评论ID和索引(用于回复功能)
|
|
|
|
|
provide('parentId', comment.id)
|
|
|
|
|
provide('index', props.index)
|
|
|
|
|
|
|
|
|
|
// 格式化时间:将时间戳转换为年月日格式
|
|
|
|
|
const formatTime = (time: any): any => {
|
|
|
|
|
let date = new Date(time)
|
|
|
|
|
let year = date.getFullYear()
|
|
|
|
|
let month = date.getMonth() + 1
|
|
|
|
|
let month = date.getMonth() + 1 // 月份从0开始,需加1
|
|
|
|
|
let day = date.getDate()
|
|
|
|
|
return year + '-' + month + '-' + day
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 响应式数据
|
|
|
|
|
const reactiveData = reactive({
|
|
|
|
|
replyContent: '' as any,
|
|
|
|
|
time: formatTime(props.comment.createTime) as any,
|
|
|
|
|
show: false as any
|
|
|
|
|
replyContent: '' as any, // 回复内容
|
|
|
|
|
time: formatTime(props.comment.createTime) as any, // 格式化后的评论时间
|
|
|
|
|
show: false as any // 控制回复表单显示状态
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 改变回复表单显示状态(隐藏)
|
|
|
|
|
const changeShow = () => {
|
|
|
|
|
reactiveData.show = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 点击回复按钮:设置回复初始内容并显示回复表单
|
|
|
|
|
const clickOnReply = () => {
|
|
|
|
|
reactiveData.replyContent = 'add reply...'
|
|
|
|
|
reactiveData.show = true
|
|
|
|
|
reactiveData.replyContent = 'add reply...' // 回复输入框初始提示文字
|
|
|
|
|
reactiveData.show = true // 显示回复表单
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...toRefs(reactiveData),
|
|
|
|
|
clickOnReply,
|
|
|
|
|
changeShow
|
|
|
|
|
...toRefs(reactiveData), // 将响应式数据转换为ref并返回
|
|
|
|
|
clickOnReply, // 回复按钮点击事件
|
|
|
|
|
changeShow // 改变回复表单显示状态的方法
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
// 评论框左侧小三角装饰
|
|
|
|
|
.reply::before {
|
|
|
|
|
content: '';
|
|
|
|
|
position: absolute;
|
|
|
|
|
@ -85,16 +111,22 @@ export default defineComponent({
|
|
|
|
|
left: -8px;
|
|
|
|
|
top: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 评论框背景样式
|
|
|
|
|
.reply {
|
|
|
|
|
background: var(--background-primary);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 回复按钮样式
|
|
|
|
|
.reply-button {
|
|
|
|
|
color: var(--text-accent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 评论内容样式:设置行高、自动换行等
|
|
|
|
|
.commentContent {
|
|
|
|
|
line-height: 26px;
|
|
|
|
|
white-space: pre-line;
|
|
|
|
|
word-wrap: break-word;
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
</style>
|