mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-02-26 16:10:49 +08:00
feat: add nested comment support
This commit is contained in:
87
open-isle-cli/src/components/CommentItem.vue
Normal file
87
open-isle-cli/src/components/CommentItem.vue
Normal 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>
|
||||
@@ -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' })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user