接下来我将提供两个Vue组件的代码,第一个是父组件postDetail.vue 第二个是子组件FeishuShare.vue。我尝试将父组件的post[]属性传递给子组件中并保存为sharedPost,请问为什么传递的是空值(父组件的post不是空值)
第一段代码
<template>
<!-- 帖子信息详情 -->
<div class="detail-container">
<div class="detail">
<div class="title-container">
<h2 class="title">{{ post.title }}</h2>
<!-- 分享按钮 -->
<FeishuShare />
<span class="date">{{ post.createDate }} 作者:<span class="author"> {{ post.author ? post.author.username : '匿名' }} </span></span>
</div>
<div class="summary-container">
<font class="summary">
{{ post.summary }}
</font>
</div>
<!-- 标签展示区域 -->
<div v-if="post.tags" class="tags-container">
<el-tag
v-for="tag in post.tags.split(/[; ;]/).map((tag) => tag.trim())"
:key="tag"
style="margin-right: 10px; margin-bottom: 5px; white-space: normal; height: auto;"
>{{ tag }}</el-tag>
</div>
<div class="content-container">
<Editor
v-model="post.content"
style="height: 500px; overflow-y: hidden;"
:default-config="editorConfig"
:mode="mode"
@onCreated="onCreated"
/>
</div>
</div>
<!-- 评论区域 -->
<div class="comment">
<div class="comment-list-container">
<div v-if="comments.length === 0" class="no-comments">暂无评论</div>
<div v-else>
<div
v-for="comment in comments"
:key="comment.id"
class="comment-item"
>
<div class="comment-item-content">
<div class="comment-header">
<div class="comment-header-left">
<el-avatar
:size="40"
icon="el-icon-user-solid"
alt="评论者头像"
:src="comment.isAnonymous? null : comment.author.avatar"
class="comment-avatar"
/>
<span class="comment-author">{{ comment.isAnonymous? '匿名' : comment.author.username }}</span>
</div>
<div class="comment-header-right">
<span class="comment-date">发表于:{{ comment.updateTime }}</span>
<el-button
type="text"
size="mini"
class="reply-btn"
@click="handleReply(comment)"
>回复</el-button>
<div v-if="replyTo === comment.id" class="replying-indicator">
正在回复此评论
</div>
<!-- 显示回复关系 -->
<div v-if="comment.parentComment" class="reply-to">
回复 <span class="reply-to-user">@{{ comment.parentComment.isAnonymous ? '匿名用户' : comment.parentComment.author.username }}</span>
</div>
<p class="comment-content">
<span v-if="comment.parentCommentId" class="reply-to">
回复 @{{ getReplyToUsername(comment) }}:
</span>
<span v-html="comment.content" />
</p>
</div>
</div>
</div>
</div>
<pagination
v-show="total > 0"
:total="total"
:page.sync="listQuery.page"
:limit.sync="listQuery.size"
@pagination="fetchPostComments"
/>
</div>
</div>
</div>
<div class="comment-form">
<!-- 发表评论表单 -->
<el-form
ref="commentForm"
:model="newComment"
>
<p v-if="!replyTo">发表评论</p>
<p v-else>
正在回复 <span class="replying-to">@{{ replyingToUsername }}</span>
<el-button type="text" size="mini" @click="cancelReply">取消回复</el-button>
</p>
<el-form-item class="comments-content">
<!-- <el-input
v-model="newComment.content"
type="textarea"
placeholder="请输入内容"
rows="8"
maxlength="1000"
show-word-limit
/> -->
<div style="border: 1px solid #ccc;">
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editor"
:default-config="toolbarConfig2"
:mode="mode"
/>
<Editor
v-model="newComment.content"
style="height: 500px; overflow-y: hidden;"
:default-config="editorConfig2"
:mode="mode"
@onCreated="onCreated"
/>
</div>
</el-form-item>
<el-form-item label="匿名">
<el-switch
v-model="newComment.isAnonymous"
active-text="是"
inactive-text="否"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitComment">提交评论</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import waves from '@/directive/waves' // waves directive
import Pagination from '@/components/Pagination'
import store from '@/store'
import { addComment, getPostComments, getPostDetail } from '@/api/post'
import { getToken } from '@/utils/auth'
import FeishuShare from './FeishuShare.vue'
export default {
components: { Pagination, Editor, Toolbar ,FeishuShare}, // 注册组件
directives: { waves },
data() {
var config = {
placeholder: '请输入内容....',
MENU_CONF: {}
}
config = this.setConfig(config)
return {
editor: null,
toolbarConfig2: {},
editorConfig: {
placeholder: '',
readOnly: true
},
editorConfig2: config,
mode: 'default', // or 'simple'
// 以上为富文本编辑器参数
postId: 0,
post: {
id: 0,
title: '',
content: '',
author: '',
createDate: '',
updateDate: '',
userId: 0,
avatar: '',
tags: ''
},
comments: [],
replyTo: null, // 当前回复的评论ID
replyingToUsername: '', // 正在回复的用户名
newComment: {
id: 0,
isAnonymous: false,
content: '',
parentCommentId: null
},
total: 0,
listLoading: true,
listQuery: {
page: 1,
size: 10
},
userInfoMap: {}
// editorConfig: {
// height: 150,
// showUpload: false,
// menubar: '',
// toolbar: [
// 'undo redo forecolor backcolor bold italic underline strikethrough alignleft aligncenter alignright'
// ]
// }
}
},
created() {
this.postId = Number(this.$route.params.id)
if (!this.postId || isNaN(this.postId) || this.postId <= 0) {
this.$message.error('帖子ID无效')
this.$router.push('/')
return
}
this.newComment.id = this.postId
this.fetchPostDetails()
this.fetchPostComments()
},
methods: {
setConfig(editorConfig) {
var temp
if (store.getters.token) {
temp = getToken()
}
editorConfig.MENU_CONF['uploadImage'] = {
server: '/api/post/upload/image',
maxFileSize: 10 * 1024 * 1024,
headers: {
'X-Token': temp
}
}
editorConfig.MENU_CONF['uploadVideo'] = {
server: '/api/post/upload/video',
maxFileSize: 100 * 1024 * 1024,
headers: {
'X-Token': temp
}
}
editorConfig.MENU_CONF['codeSelectLang'] = {
codeLangs: [
{ text: 'CSS', value: 'css' },
{ text: 'HTML', value: 'html' },
{ text: 'XML', value: 'xml' }
]
}
return editorConfig
},
onCreated(editor) {
this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
},
beforeDestroy() {
const editor = this.editor
if (editor == null) return
editor.destroy() // 组件销毁时,及时销毁编辑器
},
fetchPostDetails() {
getPostDetail(this.postId)
.then((response) => {
this.post = response.data
if (!this.post.summary) {
this.post.summary = '无概要信息'
}
this.fetchPostComments()
})
.catch((error) => {
console.error('获取帖子详情失败:', error)
this.$message.error('获取帖子详情失败')
})
},
getReplyToUsername(comment) {
const parentComment = this.comments.find(c => c.id === comment.parentCommentId)
return parentComment ? (parentComment.isAnonymous ? '匿名用户' : parentComment.author.username) : ''
},
fetchPostComments() {
const data = {
id: this.postId,
page: this.listQuery.page,
size: this.listQuery.size
}
getPostComments(data)
.then((response) => {
this.comments = response.data.content
this.total = response.data.totalElements
this.listLoading = false
setTimeout(() => {
this.listLoading = false
}, 1.5 * 1000)
})
},
handleReply(comment) {
this.replyTo = comment.id
this.replyingToUsername = comment.isAnonymous ? '匿名用户' : comment.author.username
this.newComment.parentCommentId = comment.id
this.$nextTick(() => {
this.$refs.commentForm.$el.querySelector('textarea').focus()
})
},
cancelReply() {
this.replyTo = null
this.replyingToUsername = ''
this.newComment.parentCommentId = null
},
submitComment() {
this.newComment.id = this.postId
if (!this.newComment.content.trim()) {
this.$message.error('评论内容不能为空')
return
}
addComment(this.newComment)
.then((response) => {
this.$message.success(this.replyTo ? '回复成功' : '评论成功')
this.newComment.content = ''
this.newComment.parentCommentId = null
this.replyTo = null
this.replyingToUsername = ''
this.fetchPostComments()
})
.catch((error) => {
this.$message.error('发布评论失败,请稍后重试')
console.error(error)
})
}
}
}
</script>
<style lang="scss" scoped>
.detail-container {
padding:20px;
background-color: #f7f8fa;
min-height: inherit;
.detail {
background-color: white;
padding: 20px;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
.tags-container {
margin: 10px 0;
padding: 10px 0;
border-top: 1px solid #eee;
border-bottom: 1px solid #eee;
display: flex;
flex-wrap: wrap;
align-items: center;
}
.title-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 20px;
.title {
color: #3e9ece;
margin-bottom: 10px;
text-align: center;
word-break: break-word;
}
.date {
font-size: 12px;
text-align: center;
line-height: 20px;
color: #999;
}
.author {
font-size: 14px;
color: black;
}
}
.summary-container{
border: #ebebeb 1px solid;
background: #f8f8f8;
font-size: 12px;
margin: 20px 0 10px;
padding: 10px;
line-height: 20px;
text-indent: 2em;
border-radius: 4px;
.summary {
color: #003048;
}
}
.content-container {
margin: 20px 0;
padding-bottom: 20px;
.content {
max-height: none;
overflow-y: auto;
word-break: break-word;
line-height: 1.6;
}
}
}
.comment {
.reply-to {
color: #67c23a;
font-weight: bold;
margin-right: 5px;
}
.replying-indicator {
color: #67c23a;
font-size: 12px;
margin: 5px 0;
padding: 3px 8px;
background-color: #f0f9eb;
border-radius: 4px;
display: inline-block;
}
background: white;
border: 1px solid #ebeef5;
border-radius: 4px;
padding: 20px;
margin-top: 20px;
.comment-list-container {
overflow-y: auto;
.no-comments {
text-align: center;
color: #999;
padding: 20px;
}
.comment-item {
margin-bottom: 15px;
border-bottom: 1px solid #ebeef5;
padding-bottom: 15px;
&:last-child {
border-bottom: none;
padding-bottom: 0;
}
.comment-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
}
.comment-header-left {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
flex-grow: 1;
gap: 10px;
min-width: 80px;
}
.comment-header-right {
display: flex;
flex-direction: column;
align-items: flex-start;
flex-grow: 20;
margin-left: 20px;
}
.comment-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
}
.comment-author,
.comment-date {
font-size: 12px;
color: #999;
}
.reply-to {
font-size: 12px;
color: #666;
margin: 5px 0;
.reply-to-user {
color: #409EFF;
font-weight: bold;
}
}
.comment-content {
margin-top: 5px;
word-break: break-word;
line-height: 1.6;
}
}
}
}
.comment-form {
margin-top: 20px;
padding: 20px;
background: white;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
.replying-to {
color: #409EFF;
font-weight: bold;
margin: 0 5px;
}
}
}
</style>
<style src="@wangeditor/editor/dist/css/style.css"></style>
第二段代码
<template>
<div class="feishu-share-btn">
<el-button
class="share-btn"
type="primary" size="small" icon="el-icon-share"
@click="dialogVisible=true;fetchAllUsers()" >
shareToYesv
</el-button>
<el-dialog
title="分享"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose">
<div class="mainbody">
<el-select v-model="value" filterable placeholder="请输入姓名/群组名">
<el-option
v-for="item in options"
:key="item.uid"
:label="item.username"
:value="item.uid">
</el-option>
</el-select>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false,handleShare()">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Axios from 'axios';
import { findAllUsers } from '@/api/user';
import { options } from 'dropzone';
import { sharePost } from '@/api/post';
import PostDetail from './postDetail.vue';
export default {
props:['postInfo'],
data() {
return {
dialogVisible: false,
options:[],
value: '',
sharedUserId:'',
sharedPost:this.$parent.post,
};
},
methods: {
handleClose(done) {
this.$confirm('确认关闭?')
.then(_ => {
done();
})
.catch(_ => {});
},
async handleShare(){
try{
if(this.value=='')
{
console.log('please select');
}
console.log(this.sharedPost);
this.sharedUserId=this.value;
const response=await sharePost(sharedPost,sharedUserId)
}catch(error)
{
console.log('分享失败');
}
},
async fetchAllUsers(){
try{
const response=await findAllUsers();
//List<User> fetchResult;
//fetchResult=response.data;
this.options=response.data;
//删除admin
this.options=this.options.filter(item=>item.username!='admin');
}catch(error){
console.error('获取分享列表失败');
}
},
mounted:{
}
}
};
</script>
<style>
.feishu-share-btn {
min-width: 100%;
height: 40px;
position: relative;
display:flex;
justify-content:flex-end;
}
.share-btn {
position: relative;
right: 10px;
top: 10px;
}
</style>
最新发布