108 lines
2.7 KiB
Vue
108 lines
2.7 KiB
Vue
<template>
|
||
<!-- 限制递归深度 -->
|
||
<view v-if="level <= maxLevel" class="comment-item" :style="{'margin-left': level * 15 + 'px'}">
|
||
<view class="comment-content">
|
||
<view class="comment-header">
|
||
<image class="comment-avatar" :src="comment.pusherPortrait" mode="aspectFill"></image>
|
||
<view class="comment-info">
|
||
<text class="comment-username">{{ comment.pusherName }}</text>
|
||
<text class="comment-time">{{ formatTime(comment.createdAt) }}</text>
|
||
</view>
|
||
<view class="comment-actions">
|
||
<text class="reply-btn" @tap="handleReply">回复</text>
|
||
</view>
|
||
</view>
|
||
<view class="comment-text">
|
||
<text>{{ comment.content }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 回复输入框 -->
|
||
<view v-if="replyingTo === comment.id" class="reply-input-container">
|
||
<input
|
||
class="reply-input"
|
||
v-model="replyContent"
|
||
:placeholder="`回复@${comment.pusherName}`"
|
||
/>
|
||
<button class="reply-btn" @tap="submitReply">发送</button>
|
||
<button class="cancel-btn" @tap="cancelReply">取消</button>
|
||
</view>
|
||
|
||
<!-- 子评论(限制递归) -->
|
||
<view class="children-comments">
|
||
<comment-item
|
||
v-for="child in comment.children"
|
||
:key="child.id"
|
||
:comment="child"
|
||
:level="level + 1"
|
||
:max-level="maxLevel"
|
||
:replying-to="replyingTo"
|
||
@reply="$emit('reply', $event)"
|
||
@submit-reply="$emit('submit-reply', $event)"
|
||
@cancel-reply="$emit('cancel-reply')"
|
||
></comment-item>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: "CommentItem",
|
||
props: {
|
||
comment: Object,
|
||
level: { type: Number, default: 0 },
|
||
maxLevel: { type: Number, default: 3 }, // 限制最大嵌套层级
|
||
replyingTo: String
|
||
},
|
||
data() {
|
||
return {
|
||
replyContent: ""
|
||
};
|
||
},
|
||
methods: {
|
||
handleReply() {
|
||
this.$emit("reply", this.comment.id);
|
||
},
|
||
submitReply() {
|
||
if (!this.replyContent.trim()) return;
|
||
this.$emit("submit-reply", {
|
||
parentId: this.comment.id,
|
||
content: this.replyContent
|
||
});
|
||
this.replyContent = "";
|
||
},
|
||
cancelReply() {
|
||
this.$emit("cancel-reply");
|
||
},
|
||
formatTime(time) {
|
||
// 简化时间格式化(小程序兼容)
|
||
return new Date(time).toLocaleString();
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 使用px单位 */
|
||
.comment-item {
|
||
margin-bottom: 15px;
|
||
border-left: 2px solid #eee;
|
||
padding-left: 10px;
|
||
}
|
||
|
||
.comment-avatar {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.reply-input-container {
|
||
display: flex;
|
||
margin-top: 10px;
|
||
}
|
||
.reply-input {
|
||
flex: 1;
|
||
border: 1px solid #ddd;
|
||
padding: 5px;
|
||
}
|
||
</style> |