更多操作 ---> 评论组件的封装
评论:
1、评论列表默认加载10条,下拉加载下一页。使用的是vant的list组件load事件
2、回复默认只展示3条,超出隐藏,点击【展开全部评论】加载剩下的回复,点击【收起】回到默认状态
3、点击评论者可以回复当前评论,input中显示回复的谁,并聚焦 this.$refs.inputRef.focus()
4、点击【评论】按钮打开评论popup,而【操作】和【评论】是兄弟组件,所以这里使用observer传值的方式打开评论列表
Comment.vue
<template> <van-popup v-model="show" v-if="show" position="bottom" class="comment-popup" :style="{ height: '80%' }"> <header>评论header> <van-list v-model="loadMoreLoading" @load="loadMore" ref='vanListRef' offset='50'> <template v-if="listData.length > 0"> <div class="crad" v-for="(item,index) in listData" :key="index"> <div class="commentRow" @click="onCommentRow(item,index)"> <div class="row head"> <div class="left">{{item.userName}}div> <div class="right">{{item.createTime}}div> div> <div class="row"> <div class="content">{{item.content}}div> div> div> <template v-if="item.replyVOList&&item.replyVOList.length"> <div v-for="(obj,oIndex) in item.isOpen?item.replyVOList : item.replyVOList.slice(0,3)" :key="oIndex" class="commentRow replyRow" @click="onCommentReply(item,obj,index)"> <div class="row head"> <div class="left">{{obj.userName}}div> <div class="right">{{obj.createTime}}div> div> <div class="row"> <div class="content">回复<span class="contentSpan">@{{obj.replyUserName}}span>:{{obj.content}}div> div> div> template> <van-loading v-if="item.loading" /> <template v-if="item.replyNum&&item.replyNum>3&&!item.loading"> <div class="shrink out replyRow" v-if="!item.isOpen" @click="onOpen(item,index,true)"> 展开全部评论 div> <div class="shrink open replyRow" v-else @click="onOpen(item,index,false)"> 收起 div> template> div> template> <div v-else class="empty-data">暂无评论div> van-list> <footer> <van-field ref="inputRef" v-model="commentContent" maxlength="500" center clearable :placeholder="replyPlaceholder || '小小的鼓励,是团队的凝聚'" /> <van-button @click="send">发送van-button> footer> van-popup> template> <script> import { getToken } from '@/utils/token' import { getCommentList, insertComment, addReply, getLastReplyList } from '@/api/project' export default { components: {}, props: { commentParams: { type: Object, require: true } }, data() { return { show: false, queryParams: { page: 1, pageSize: 10, mid: this.commentParams.mid, // 项目报:flowTrackId 拜访计划/拜访反馈:id mtype: this.commentParams.mtype // 1=项目报 2=拜访计划 3=拜访反馈 }, totalPages: 0, // 总页数 listData: [], //评论列表 sendItem: {}, replyPlaceholder: '', // 评论输入框中的placeholder文案 commentContent: '', // 评论输入框中输入的内容 loadMoreLoading: false // 加载更多loading } }, computed: { userId: () => { const token = getToken() return Number(token.split('-')[0]) } }, created() { this.$observer.$on('openComment', () => { this.queryParams.page = 1 this.fetchProjectLog() this.show = true }) }, beforeDestroy() { this.$observer.$off('openComment') }, methods: { onOpen(item, index, isOpen) { this.setOpen({ index, isOpen }) }, onCommentRow(item, index) { let { userId } = this if (item.userId != userId) { item.commentId = item.id item.index = index this.setComment(item) } }, onCommentReply(item, obj, index) { let { userId } = this if (obj.userId != userId) { obj.commentId = item.id obj.index = index this.setComment(obj) } }, fetchProjectLog() { const { queryParams } = this this.$vux.loading.show('加载中...') return getCommentList(queryParams) .then(res => { this.$vux.loading.hide() let { data, totalPages } = res if (queryParams.page === 1) { if (data && data.length) { let arr = data.map(item => { item.isOpen = false item.loading = false return item }) this.listData = arr } else { this.listData = [] } } else { if (data && data.length) { let arr = data.map(item => { item.isOpen = false item.loading = false return item }) this.listData = [...this.listData, ...arr] } else { this.listData = [] } } this.totalPages = totalPages return res }) .catch(() => { this.$vux.loading.hide() }) }, setComment(item) { this.sendItem = { ...item } this.replyPlaceholder = '回复' + item.userName + ':' this.$refs.inputRef.focus() // 聚焦 }, setOpen(obj) { let { index, isOpen } = obj let item = this.listData[index] if (isOpen && item.replyVOList.length === 3 && item.replyNum > 3) { item.loading = true getLastReplyList({ commentId: item.id }).then(result => { if (result.data && result.data.length) { item.replyVOList = [...item.replyVOList, ...result.data] item.loading = false item.isOpen = isOpen } }) } else { item.isOpen = isOpen } }, send() { const { mid, mtype } = this.commentParams const { commentContent, replyPlaceholder } = this if (replyPlaceholder && commentContent) { let { commentId, userId, index } = this.sendItem const params = { content: commentContent, commentId, replyUser: userId } addReply(params) .then(res => { if (res.data) { this.commentContent = '' let listData = [...this.listData] listData[index].replyNum++ listData[index].replyVOList.push(res.data) this.$set(this, 'listData', listData) this.$vux.toast.text('回复成功') this.replyPlaceholder = '' } else { this.$vux.toast.text(res.msg || '回复失败') } }) .catch(() => { this.$vux.toast.text('回复失败') }) } else { const params = { mid, mtype, content: commentContent } insertComment(params) .then(res => { if (res.data) { this.commentContent = '' this.queryParams.page = 1 this.fetchProjectLog() this.$vux.toast.text('评论成功') } else { this.$vux.toast.text(res.msg || '评论失败') } }) .catch(() => { this.$vux.toast.text('评论失败') }) } }, loadMore() { const { totalPages } = this const { page } = this.queryParams if (totalPages > page) { this.queryParams.page++ this.fetchProjectLog().then(res => { if (res.success) { this.loadMoreLoading = false } }) } else { this.loadMoreLoading = false } } } } script>
css:
MoreOperations.vue
<template> <div class="more-operations"> <transition name="popup"> <div class="popup" v-show="isShow" @click="handleClose"> <div class="btns"> <div @click="handleEdit">编辑div> <div @click.stop="handleDelete">删除div> <div @click="handleComment">评论div> div> div> transition> div> template> <script> export default { props: { visible: { type: Boolean, require: true } }, computed: { isShow: { get() { return this.visible }, set(flag) { this.$emit('update:visible', flag) } } }, methods: { handleEdit() { this.$emit('edit') }, handleDelete() { this.$emit('delete') }, handleClose() { this.isShow = false }, handleComment() { this.$observer.$emit('openComment') } } } script>
css:
【拜访计划】使用【更多操作】和【评论】组件:
<MoreOperations :visible.sync='isShow' @edit='handleEdit' @delete='handleDelete' /> <Comment :commentParams='{mid:$route.query.id,mtype:2}' />
注:评论组件是可以重复使用的,在引入时传入不同的参数以供接口请求