mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-08-15 07:41:00 +00:00
refactor: extract comment editor component
This commit is contained in:
@@ -0,0 +1,95 @@
|
|||||||
|
<template>
|
||||||
|
<div class="comment-editor-container">
|
||||||
|
<div :id="editorId" ref="vditorElement"></div>
|
||||||
|
<div class="comment-bottom-container">
|
||||||
|
<div class="comment-submit" @click="submit">发布评论</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import Vditor from 'vditor'
|
||||||
|
import 'vditor/dist/index.css'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CommentEditor',
|
||||||
|
emits: ['submit'],
|
||||||
|
props: {
|
||||||
|
editorId: {
|
||||||
|
type: String,
|
||||||
|
default: () => 'editor-' + Math.random().toString(36).slice(2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const vditorInstance = ref(null)
|
||||||
|
|
||||||
|
const submit = () => {
|
||||||
|
if (!vditorInstance.value) return
|
||||||
|
const text = vditorInstance.value.getValue()
|
||||||
|
if (!text.trim()) return
|
||||||
|
emit('submit', text)
|
||||||
|
vditorInstance.value.setValue('')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
vditorInstance.value = new Vditor(props.editorId, {
|
||||||
|
placeholder: '说点什么...',
|
||||||
|
height: 120,
|
||||||
|
theme: 'classic',
|
||||||
|
preview: {
|
||||||
|
theme: { current: 'light' },
|
||||||
|
actions: [],
|
||||||
|
markdown: { toc: false }
|
||||||
|
},
|
||||||
|
toolbar: [
|
||||||
|
'emoji',
|
||||||
|
'bold',
|
||||||
|
'italic',
|
||||||
|
'strike',
|
||||||
|
'|',
|
||||||
|
'list',
|
||||||
|
'line',
|
||||||
|
'quote',
|
||||||
|
'code',
|
||||||
|
'inline-code',
|
||||||
|
'|',
|
||||||
|
'undo',
|
||||||
|
'redo',
|
||||||
|
'|',
|
||||||
|
'link',
|
||||||
|
'image'
|
||||||
|
],
|
||||||
|
toolbarConfig: { pin: true }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return { submit }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.comment-editor-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
border: 1px solid #e2e2e2;
|
||||||
|
}
|
||||||
|
.comment-bottom-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.comment-submit {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.comment-submit:hover {
|
||||||
|
background-color: var(--primary-color-hover);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -29,9 +29,9 @@
|
|||||||
<div class="reactions-count">1882</div>
|
<div class="reactions-count">1882</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="make-reaction-container">
|
<div class="make-reaction-container">
|
||||||
<div class="make-reaction-item comment-reaction">
|
<div class="make-reaction-item comment-reaction" @click="toggleEditor">
|
||||||
<i class="far fa-comment"></i>
|
<i class="far fa-comment"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="make-reaction-item like-reaction">
|
<div class="make-reaction-item like-reaction">
|
||||||
<i class="far fa-heart"></i>
|
<i class="far fa-heart"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<CommentEditor v-if="showEditor" @submit="submitReply" />
|
||||||
<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>
|
||||||
@@ -58,6 +59,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
import CommentEditor from './CommentEditor.vue'
|
||||||
const CommentItem = {
|
const CommentItem = {
|
||||||
name: 'CommentItem',
|
name: 'CommentItem',
|
||||||
props: {
|
props: {
|
||||||
@@ -70,15 +72,32 @@ const CommentItem = {
|
|||||||
default: 0
|
default: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup() {
|
setup(props) {
|
||||||
const showReplies = ref(false)
|
const showReplies = ref(false)
|
||||||
|
const showEditor = ref(false)
|
||||||
const toggleReplies = () => {
|
const toggleReplies = () => {
|
||||||
showReplies.value = !showReplies.value
|
showReplies.value = !showReplies.value
|
||||||
}
|
}
|
||||||
return { showReplies, toggleReplies }
|
const toggleEditor = () => {
|
||||||
|
showEditor.value = !showEditor.value
|
||||||
|
}
|
||||||
|
const submitReply = (text) => {
|
||||||
|
if (!text.trim()) return
|
||||||
|
const replyList = props.comment.reply || (props.comment.reply = [])
|
||||||
|
replyList.push({
|
||||||
|
id: Date.now(),
|
||||||
|
userName: '你',
|
||||||
|
time: new Date().toLocaleDateString('zh-CN', { month: 'numeric', day: 'numeric' }),
|
||||||
|
avatar: 'https://picsum.photos/200/200',
|
||||||
|
text,
|
||||||
|
reply: []
|
||||||
|
})
|
||||||
|
showEditor.value = false
|
||||||
|
}
|
||||||
|
return { showReplies, toggleReplies, showEditor, toggleEditor, submitReply }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CommentItem.components = { CommentItem }
|
CommentItem.components = { CommentItem, CommentEditor }
|
||||||
export default CommentItem
|
export default CommentItem
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -81,12 +81,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="comment-editor-container">
|
<CommentEditor @submit="postComment" />
|
||||||
<div id="vditor" ref="vditorElement"></div>
|
|
||||||
<div class="comment-bottom-container">
|
|
||||||
<div class="comment-submit" @click="postComment">发布评论</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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" />
|
||||||
@@ -99,7 +94,7 @@
|
|||||||
<div class="scroller-middle">
|
<div class="scroller-middle">
|
||||||
<input type="range" class="scroller-range" :max="totalPosts" :min="1" v-model.number="currentIndex"
|
<input type="range" class="scroller-range" :max="totalPosts" :min="1" v-model.number="currentIndex"
|
||||||
@input="onSliderInput" />
|
@input="onSliderInput" />
|
||||||
<div class="scroller-index" :style="indexStyle">{{ currentIndex }}/{{ totalPosts }}</div>
|
<div class="scroller-index">{{ currentIndex }}/{{ totalPosts }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="scroller-time">{{ lastReplyTime }}</div>
|
<div class="scroller-time">{{ lastReplyTime }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -110,15 +105,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import CommentItem from '../components/CommentItem.vue'
|
import CommentItem from '../components/CommentItem.vue'
|
||||||
import Vditor from 'vditor'
|
import CommentEditor from '../components/CommentEditor.vue'
|
||||||
import 'vditor/dist/index.css'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PostPageView',
|
name: 'PostPageView',
|
||||||
components: { CommentItem },
|
components: { CommentItem, CommentEditor },
|
||||||
setup() {
|
setup() {
|
||||||
const vditorInstance = ref(null)
|
|
||||||
const vditorElement = ref(null)
|
|
||||||
const tags = ref(['AI', 'Python', 'Java'])
|
const tags = ref(['AI', 'Python', 'Java'])
|
||||||
const comments = ref([
|
const comments = ref([
|
||||||
{
|
{
|
||||||
@@ -221,9 +213,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const postComment = () => {
|
const postComment = (text) => {
|
||||||
if (!vditorInstance.value) return
|
|
||||||
const text = vditorInstance.value.getValue()
|
|
||||||
if (!text.trim()) return
|
if (!text.trim()) return
|
||||||
comments.value.push({
|
comments.value.push({
|
||||||
id: comments.value.length + 1,
|
id: comments.value.length + 1,
|
||||||
@@ -233,49 +223,8 @@ export default {
|
|||||||
text,
|
text,
|
||||||
reply: []
|
reply: []
|
||||||
})
|
})
|
||||||
vditorInstance.value.setValue('')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
vditorInstance.value = new Vditor('vditor', {
|
|
||||||
placeholder: '说点什么...',
|
|
||||||
height: 120,
|
|
||||||
|
|
||||||
/* ===================== 主题相关 ===================== */
|
|
||||||
// 编辑区主题(classic|dark|light)。classic = 很淡、和浅色页面更搭
|
|
||||||
theme: 'classic',
|
|
||||||
// 预览区主题:light / dark / wechat / ant-design
|
|
||||||
preview: {
|
|
||||||
theme: {
|
|
||||||
current: 'light',
|
|
||||||
},
|
|
||||||
actions: [],
|
|
||||||
markdown: { toc: false },
|
|
||||||
},
|
|
||||||
|
|
||||||
/* ===================== 功能裁剪 ===================== */
|
|
||||||
toolbar: [
|
|
||||||
'emoji',
|
|
||||||
'bold',
|
|
||||||
'italic',
|
|
||||||
'strike',
|
|
||||||
'|',
|
|
||||||
'list',
|
|
||||||
'line',
|
|
||||||
'quote',
|
|
||||||
'code',
|
|
||||||
'inline-code',
|
|
||||||
'|',
|
|
||||||
'undo',
|
|
||||||
'redo',
|
|
||||||
'|',
|
|
||||||
'link',
|
|
||||||
'image',
|
|
||||||
],
|
|
||||||
toolbarConfig: {
|
|
||||||
pin: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
updateCurrentIndex()
|
updateCurrentIndex()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -288,7 +237,6 @@ export default {
|
|||||||
mainContainer,
|
mainContainer,
|
||||||
currentIndex,
|
currentIndex,
|
||||||
totalPosts,
|
totalPosts,
|
||||||
vditorElement,
|
|
||||||
postComment,
|
postComment,
|
||||||
onSliderInput,
|
onSliderInput,
|
||||||
onScroll: updateCurrentIndex
|
onScroll: updateCurrentIndex
|
||||||
@@ -540,30 +488,5 @@ export default {
|
|||||||
background-color: #e2e2e2;
|
background-color: #e2e2e2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-editor-container {
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 50px;
|
|
||||||
border: 1px solid #e2e2e2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-bottom-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-end;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-submit {
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
color: #fff;
|
|
||||||
padding: 10px 20px;
|
|
||||||
border-radius: 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-submit:hover {
|
|
||||||
background-color: var(--primary-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user