Merge pull request #92 from nagisa77/codex/update-commenteditor.vue-with-loading-and-disabled-state

This commit is contained in:
Tim
2025-07-06 21:33:59 +08:00
committed by GitHub
3 changed files with 52 additions and 12 deletions
+37 -8
View File
@@ -2,13 +2,24 @@
<div class="comment-editor-container"> <div class="comment-editor-container">
<div :id="editorId" ref="vditorElement"></div> <div :id="editorId" ref="vditorElement"></div>
<div class="comment-bottom-container"> <div class="comment-bottom-container">
<div class="comment-submit" @click="submit">发布评论</div> <div
class="comment-submit"
:class="{ disabled: isDisabled }"
@click="submit"
>
<template v-if="!loading">
发布评论
</template>
<template v-else>
<i class="fa-solid fa-spinner fa-spin"></i> 发布中...
</template>
</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ref, onMounted } from 'vue' import { ref, onMounted, computed } from 'vue'
import Vditor from 'vditor' import Vditor from 'vditor'
import 'vditor/dist/index.css' import 'vditor/dist/index.css'
@@ -19,17 +30,24 @@ export default {
editorId: { editorId: {
type: String, type: String,
default: () => 'editor-' + Math.random().toString(36).slice(2) default: () => 'editor-' + Math.random().toString(36).slice(2)
},
loading: {
type: Boolean,
default: false
} }
}, },
setup(props, { emit }) { setup(props, { emit }) {
const vditorInstance = ref(null) const vditorInstance = ref(null)
const text = ref('')
const isDisabled = computed(() => props.loading || !text.value.trim())
const submit = () => { const submit = () => {
if (!vditorInstance.value) return if (!vditorInstance.value || isDisabled.value) return
const text = vditorInstance.value.getValue() const value = vditorInstance.value.getValue()
if (!text.trim()) return emit('submit', value)
emit('submit', text)
vditorInstance.value.setValue('') vditorInstance.value.setValue('')
text.value = ''
} }
onMounted(() => { onMounted(() => {
@@ -60,11 +78,14 @@ export default {
'link', 'link',
'image' 'image'
], ],
toolbarConfig: { pin: true } toolbarConfig: { pin: true },
input(value) {
text.value = value
}
}) })
}) })
return { submit } return { submit, isDisabled }
} }
} }
</script> </script>
@@ -89,6 +110,14 @@ export default {
font-size: 14px; font-size: 14px;
cursor: pointer; cursor: pointer;
} }
.comment-submit.disabled {
background-color: var(--primary-color-disabled);
opacity: 0.5;
cursor: not-allowed;
}
.comment-submit.disabled:hover {
background-color: var(--primary-color-disabled);
}
.comment-submit:hover { .comment-submit:hover {
background-color: var(--primary-color-hover); background-color: var(--primary-color-hover);
} }
+7 -2
View File
@@ -40,7 +40,7 @@
</div> </div>
</div> </div>
</div> </div>
<CommentEditor v-if="showEditor" @submit="submitReply" /> <CommentEditor v-if="showEditor" @submit="submitReply" :loading="isWaitingForReply" />
<div v-if="comment.reply && comment.reply.length" class="reply-toggle" @click="toggleReplies"> <div v-if="comment.reply && comment.reply.length" class="reply-toggle" @click="toggleReplies">
{{ comment.reply.length }}条回复 {{ comment.reply.length }}条回复
</div> </div>
@@ -77,6 +77,7 @@ const CommentItem = {
setup(props) { setup(props) {
const showReplies = ref(false) const showReplies = ref(false)
const showEditor = ref(false) const showEditor = ref(false)
const isWaitingForReply = ref(false)
const toggleReplies = () => { const toggleReplies = () => {
showReplies.value = !showReplies.value showReplies.value = !showReplies.value
} }
@@ -85,9 +86,11 @@ const CommentItem = {
} }
const submitReply = async (text) => { const submitReply = async (text) => {
if (!text.trim()) return if (!text.trim()) return
isWaitingForReply.value = true
const token = getToken() const token = getToken()
if (!token) { if (!token) {
toast.error('请先登录') toast.error('请先登录')
isWaitingForReply.value = false
return return
} }
try { try {
@@ -120,13 +123,15 @@ const CommentItem = {
} }
} catch (e) { } catch (e) {
toast.error('回复失败') toast.error('回复失败')
} finally {
isWaitingForReply.value = false
} }
} }
const copyCommentLink = () => { const copyCommentLink = () => {
const link = `${location.origin}${location.pathname}#comment-${props.comment.id}` const link = `${location.origin}${location.pathname}#comment-${props.comment.id}`
navigator.clipboard.writeText(link) navigator.clipboard.writeText(link)
} }
return { showReplies, toggleReplies, showEditor, toggleEditor, submitReply, copyCommentLink, renderMarkdown } return { showReplies, toggleReplies, showEditor, toggleEditor, submitReply, copyCommentLink, renderMarkdown, isWaitingForReply }
} }
} }
CommentItem.components = { CommentItem, CommentEditor } CommentItem.components = { CommentItem, CommentEditor }
+8 -2
View File
@@ -65,7 +65,7 @@
</div> </div>
</div> </div>
<CommentEditor @submit="postComment" /> <CommentEditor @submit="postComment" :loading="isWaitingPostingComment" />
<div class="comments-container"> <div class="comments-container">
<CommentItem v-for="comment in comments" :key="comment.id" :comment="comment" :level="0" ref="postItems" /> <CommentItem v-for="comment in comments" :key="comment.id" :comment="comment" :level="0" ref="postItems" />
@@ -112,6 +112,7 @@ export default {
const tags = ref([]) const tags = ref([])
const comments = ref([]) const comments = ref([])
const isWaitingFetchingPost = ref(false); const isWaitingFetchingPost = ref(false);
const isWaitingPostingComment = ref(false);
const postTime = ref('') const postTime = ref('')
const postItems = ref([]) const postItems = ref([])
const mainContainer = ref(null) const mainContainer = ref(null)
@@ -169,9 +170,11 @@ export default {
const postComment = async (text) => { const postComment = async (text) => {
if (!text.trim()) return if (!text.trim()) return
isWaitingPostingComment.value = true
const token = getToken() const token = getToken()
if (!token) { if (!token) {
toast.error('请先登录') toast.error('请先登录')
isWaitingPostingComment.value = false
return return
} }
try { try {
@@ -188,6 +191,8 @@ export default {
} }
} catch (e) { } catch (e) {
toast.error('评论失败') toast.error('评论失败')
} finally {
isWaitingPostingComment.value = false
} }
} }
@@ -227,7 +232,8 @@ export default {
onScroll: updateCurrentIndex, onScroll: updateCurrentIndex,
copyPostLink, copyPostLink,
renderMarkdown, renderMarkdown,
isWaitingFetchingPost isWaitingFetchingPost,
isWaitingPostingComment
} }
} }
} }