11
This commit is contained in:
@@ -1,21 +1,65 @@
|
||||
<template>
|
||||
<div id="message_all">
|
||||
<!-- 上:标题区 -->
|
||||
<div class="message-header">
|
||||
<h1>留言板</h1>
|
||||
</div>
|
||||
<!-- 中:留言内容区 -->
|
||||
<div class="message-board">
|
||||
<!-- 留言内容区 -->
|
||||
<div class="message-list">
|
||||
<div class="message-item" v-for="msg in messages" :key="msg.id">
|
||||
<div class="message-nickname">{{ msg.nickname }}</div>
|
||||
<div class="message-content">{{ msg.content }}</div>
|
||||
<div class="message-time">{{ msg.time }}</div>
|
||||
<h3>留言板</h3>
|
||||
<div class="message-item" v-for="msg in messages" :key="msg.id" @mouseenter="hoverId = msg.id"
|
||||
@mouseleave="hoverId = null">
|
||||
<div>
|
||||
<!-- 头像 -->
|
||||
<img src="https://www.gravatar.com/avatar?d=mp&s=40" alt="头像" class="message-avatar" />
|
||||
</div>
|
||||
<div>
|
||||
<!-- 评论内容 -->
|
||||
<div class="message-item-top">
|
||||
<div class="message-nickname">{{ msg.nickname }}</div>
|
||||
<div class="message-time">{{ msg.time }}</div>
|
||||
</div>
|
||||
<div class="message-content">{{ msg.content }}</div>
|
||||
<!-- 回复按钮 -->
|
||||
<div class="message-item-bottom">
|
||||
<button class="reply-btn" @click="message_click(msg)"
|
||||
:class="{ visible: hoverId === msg.id }">回复</button>
|
||||
</div>
|
||||
<!-- 回复列表 -->
|
||||
<div v-if="msg.replies && msg.replies.length" class="replies">
|
||||
<div class="reply-item" v-for="reply in msg.replies" :key="reply.id">
|
||||
|
||||
<div>
|
||||
<!-- 头像 -->
|
||||
<img src="https://www.gravatar.com/avatar?d=mp&s=40" alt="头像" class="message-avatar" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="message-item-top ">
|
||||
<div class="message-nickname">{{ reply.nickname }}</div>
|
||||
<div class="message-time">{{ reply.time }}</div>
|
||||
</div>
|
||||
<div class="message-content">{{ reply.content }}</div>
|
||||
<!-- 回复按钮 -->
|
||||
<div class="message-item-bottom">
|
||||
<button class="reply-btn" @click="message_click(msg)"
|
||||
:class="{ visible: hoverId === msg.id }">回复</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="messages.length === 0" class="message-empty">还没有留言,快来抢沙发吧!</div>
|
||||
</div>
|
||||
<!-- 下:留言输入区 -->
|
||||
<!-- 留言输入区 -->
|
||||
<div class="message-form-section">
|
||||
<h2>发送评论(请正确填写邮箱地址,否则将会当成垃圾评论处理)</h2>
|
||||
<div v-if="message_all.id" class="reply-preview">
|
||||
<span>
|
||||
正在回复 <b>{{ message_all.nickname }}</b> 的评论 :
|
||||
</span>
|
||||
<div class="reply-preview-content">
|
||||
{{ message_all.content }}
|
||||
</div>
|
||||
<button class="reply-cancel-btn" @click="post_comment_reply_cancel">取消回复</button>
|
||||
</div>
|
||||
<el-form :model="form" label-width="0">
|
||||
<el-form-item>
|
||||
<el-input v-model="form.content" placeholder="评论内容" type="textarea" rows="4" clearable />
|
||||
@@ -31,9 +75,11 @@
|
||||
<el-input v-model="form.captcha" placeholder="验证码" clearable />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">发送</el-button>
|
||||
</el-form-item>
|
||||
<div class="form-input-row">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">发送</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -41,14 +87,41 @@
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
|
||||
const message_all = ref({})
|
||||
const hoverId = ref(null)
|
||||
const messages = ref([
|
||||
{ id: 1, nickname: 'A', content: '这里是A!', time: '2025-09-26 10:00' },
|
||||
{ id: 2, nickname: 'B', content: '这里是B!', time: '2025-09-26 10:05' },
|
||||
{ id: 3, nickname: 'C', content: '这里是C!', time: '2025-09-26 10:10' }
|
||||
{
|
||||
id: 1,
|
||||
nickname: 'A',
|
||||
content: '这里是A!',
|
||||
time: '2025-09-26 10:00',
|
||||
replies: [
|
||||
{
|
||||
id: 4,
|
||||
nickname: 'B',
|
||||
content: 'A,我来回复你!',
|
||||
time: '2025-09-26 10:20'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
nickname: 'B',
|
||||
content: '这里是B!',
|
||||
time: '2025-09-26 10:05',
|
||||
replies: []
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
nickname: 'C',
|
||||
content: '这里是C!',
|
||||
time: '2025-09-26 10:10',
|
||||
replies: []
|
||||
}
|
||||
])
|
||||
|
||||
const form = reactive({
|
||||
replyid: null,
|
||||
content: '',
|
||||
nickname: '',
|
||||
email: '',
|
||||
@@ -57,27 +130,51 @@ const form = reactive({
|
||||
|
||||
const onSubmit = () => {
|
||||
if (!form.content || !form.nickname) return
|
||||
messages.value.push({
|
||||
id: messages.value.length + 1,
|
||||
nickname: form.nickname,
|
||||
content: form.content,
|
||||
time: new Date().toLocaleString()
|
||||
})
|
||||
if (form.replyid) {
|
||||
// 回复模式
|
||||
const parent = messages.value.find(msg => msg.id === form.replyid)
|
||||
if (parent) {
|
||||
parent.replies = parent.replies || []
|
||||
parent.replies.push({
|
||||
id: Date.now(),
|
||||
nickname: form.nickname,
|
||||
content: form.content,
|
||||
time: new Date().toLocaleString()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// 普通留言
|
||||
messages.value.push({
|
||||
id: Date.now(),
|
||||
nickname: form.nickname,
|
||||
content: form.content,
|
||||
time: new Date().toLocaleString(),
|
||||
replies: []
|
||||
})
|
||||
}
|
||||
form.replyid = null
|
||||
form.content = ''
|
||||
form.nickname = ''
|
||||
form.email = ''
|
||||
form.captcha = ''
|
||||
message_all.value = {}
|
||||
}
|
||||
const message_click = (msg) => {
|
||||
message_all.value = msg
|
||||
form.replyid = msg.id
|
||||
// 可选:填充回复内容到输入框
|
||||
form.content = `@${msg.nickname} `
|
||||
}
|
||||
const post_comment_reply_cancel = () => {
|
||||
message_all.value = {}
|
||||
form.content = ''
|
||||
form.replyid = null
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#message_all {
|
||||
width: var(--content-width);
|
||||
margin: var(--content-margin);
|
||||
}
|
||||
|
||||
.message-header {
|
||||
background: rgba(102, 161, 216, 0.9);
|
||||
border-radius: 12px;
|
||||
padding: 20px 0;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
.message-board {
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
.message-list {
|
||||
@@ -88,23 +185,46 @@ const onSubmit = () => {
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.replies {
|
||||
margin-left: 40px;
|
||||
border-top: 2px solid #eee;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.message-item {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 14px 18px;
|
||||
margin-bottom: 12px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
position: relative;
|
||||
margin-left: 1%;
|
||||
}
|
||||
|
||||
.message-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
margin-right: 12px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.message-item-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.message-nickname {
|
||||
font-weight: bold;
|
||||
color: #409eff;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
margin-bottom: 4px;
|
||||
color: #333;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.message-time {
|
||||
@@ -113,6 +233,30 @@ const onSubmit = () => {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.message-item-bottom {
|
||||
height: 45px;
|
||||
/* 固定高度以防跳动 */
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.reply-btn {
|
||||
background: #409eff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 4px 12px;
|
||||
margin-top: 4px;
|
||||
transition: background 0.2s;
|
||||
float: right;
|
||||
visibility: hidden;
|
||||
/* 默认隐藏但占位 */
|
||||
}
|
||||
|
||||
.message-item:hover .reply-btn,
|
||||
.reply-btn.visible {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.message-empty {
|
||||
color: #bbb;
|
||||
text-align: center;
|
||||
@@ -132,6 +276,38 @@ const onSubmit = () => {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.reply-preview {
|
||||
background: #f0f9ff;
|
||||
border-left: 4px solid #409eff;
|
||||
padding: 10px 16px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.reply-preview-content {
|
||||
margin-top: 6px;
|
||||
color: #666;
|
||||
font-size: 0.98rem;
|
||||
}
|
||||
|
||||
.reply-cancel-btn {
|
||||
background: #fff;
|
||||
color: #409eff;
|
||||
border: 1px solid #409eff;
|
||||
border-radius: 6px;
|
||||
padding: 2px 10px;
|
||||
cursor: pointer;
|
||||
margin-top: 8px;
|
||||
font-size: 0.95rem;
|
||||
transition: background 0.2s, color 0.2s;
|
||||
}
|
||||
|
||||
.reply-cancel-btn:hover {
|
||||
background: #409eff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.form-input-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
@@ -149,7 +325,7 @@ const onSubmit = () => {
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
#message_all {
|
||||
.message-board {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user