feat: add nested comment support

This commit is contained in:
Tim
2025-07-04 11:05:23 +08:00
parent b2436c4e8b
commit 1011584756
2 changed files with 98 additions and 47 deletions

View File

@@ -0,0 +1,87 @@
<template>
<div class="info-content-container" :style="{ marginLeft: level * 20 + 'px' }">
<div class="user-avatar-container">
<div class="user-avatar-item">
<img class="user-avatar-item-img" :src="comment.avatar" alt="avatar" />
</div>
</div>
<div class="info-content">
<div class="info-content-header">
<div class="user-name">{{ comment.userName }}</div>
<div class="post-time">{{ comment.time }}</div>
</div>
<div class="info-content-text">
{{ comment.text }}
</div>
<div class="article-footer-container">
<div class="reactions-container">
<div class="reactions-viewer">
<div class="reactions-viewer-item-container">
<div class="reactions-viewer-item">🤣</div>
<div class="reactions-viewer-item"></div>
<div class="reactions-viewer-item">👏</div>
</div>
<div class="reactions-count">1882</div>
</div>
<div class="make-reaction-container">
<div class="make-reaction-item like-reaction">
<i class="far fa-heart"></i>
</div>
<div class="make-reaction-item copy-link">
<i class="fas fa-link"></i>
</div>
</div>
</div>
</div>
<div v-if="comment.reply && comment.reply.length" class="reply-toggle" @click="toggleReplies">
{{ comment.reply.length }}条回复
</div>
<div v-if="showReplies" class="reply-list">
<CommentItem
v-for="r in comment.reply"
:key="r.id"
:comment="r"
:level="level + 1"
/>
</div>
</div>
</div>
</template>
<script>
import { ref } from 'vue'
const CommentItem = {
name: 'CommentItem',
props: {
comment: {
type: Object,
required: true
},
level: {
type: Number,
default: 0
}
},
setup() {
const showReplies = ref(false)
const toggleReplies = () => {
showReplies.value = !showReplies.value
}
return { showReplies, toggleReplies }
}
}
CommentItem.components = { CommentItem }
export default CommentItem
</script>
<style scoped>
.reply-toggle {
cursor: pointer;
color: var(--primary-color);
margin-top: 10px;
user-select: none;
}
.reply-list {
margin-top: 10px;
}
</style>

View File

@@ -82,51 +82,13 @@
</div>
<div class="comments-container">
<div class="info-content-container" v-for="comment in comments" :key="comment.id" ref="postItems">
<div class="user-avatar-container">
<div class="user-avatar-item">
<img class="user-avatar-item-img" :src="comment.avatar" alt="avatar">
</div>
</div>
<div class="info-content">
<div class="info-content-header">
<div class="user-name">{{ comment.userName }}</div>
<div class="post-time">{{ comment.time }}</div>
</div>
<div class="info-content-text">
{{ comment.text }}
</div>
<div class="article-footer-container">
<div class="reactions-container">
<div class="reactions-viewer">
<div class="reactions-viewer-item-container">
<div class="reactions-viewer-item">
🤣
</div>
<div class="reactions-viewer-item">
</div>
<div class="reactions-viewer-item">
👏
</div>
</div>
<div class="reactions-count">1882</div>
</div>
<div class="make-reaction-container">
<div class="make-reaction-item like-reaction">
<i class="far fa-heart"></i>
</div>
<div class="make-reaction-item copy-link">
<i class="fas fa-link"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<CommentItem
v-for="comment in comments"
:key="comment.id"
:comment="comment"
:level="0"
ref="postItems"
/>
</div>
</div>
@@ -146,9 +108,11 @@
<script>
import { ref, computed, onMounted } from 'vue'
import CommentItem from '../components/CommentItem.vue'
export default {
name: 'PostPageView',
components: { CommentItem },
setup() {
const tags = ref(['AI', 'Python', 'Java'])
const comments = ref([
@@ -237,7 +201,7 @@ export default {
const updateCurrentIndex = () => {
const scrollTop = mainContainer.value ? mainContainer.value.scrollTop : 0
for (let i = 0; i < postItems.value.length; i++) {
const el = postItems.value[i]
const el = postItems.value[i].$el
if (el.offsetTop + el.offsetHeight > scrollTop) {
currentIndex.value = i + 1
break
@@ -246,7 +210,7 @@ export default {
}
const onSliderInput = () => {
const target = postItems.value[currentIndex.value - 1]
const target = postItems.value[currentIndex.value - 1]?.$el
if (target && mainContainer.value) {
mainContainer.value.scrollTo({ top: target.offsetTop, behavior: 'instant' })
}