更多操作 ---> 评论组件的封装


     

评论:

  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}' />

  注:评论组件是可以重复使用的,在引入时传入不同的参数以供接口请求