移动端头条新闻类项目文章评论功能

1,066 阅读4分钟

功能需求

  1. 需要把用户对文章的评论渲染到文章的最底部
  2. 用户可以及时发布对文章的评论
  3. 其他用户可以对评论进行回复和点赞的动作
  • 开发功能注意点:这里后端提供的关于文章评论和回复用户评论的接口是一个接口,后端是通过对接口里传递参数的不同来决定传给前端怎样的数据,所以在做这个功能的时候有一些接口需要的数据需要传递动态数据,对于动态数据的处理需要比较注意,否则接口就有可能出现调不同的问题

WechatIMG535.jpeg

文章评论功能

  • 搭建静态页面:这里使用了vant中的list组件和cell单元格组件,搭建评论的页面
  • 封装组件:把文章评论的页面封装成组件,在文章详情的正文下面插入
  • 功能技术点1:这里考虑到后续要在父组件文章详情页面中对同一个数剧进行发表评论和渲染评论列表,需要对数据进行添加,所以在父组件中提前定义了一个数组,用父传子的方式传给文章评论页面组件,这样评论文章的信息和文章评论的渲染就可以对同个数据进行添加和渲染
  • 渲染评论列表功能逻辑:组件获取到接口所需要的文章id,在评论页面组件中发起网络请求调用接口,传入所需要的参数,利用拿到的数据将页面渲染出来
  // 获取评论详情内容
     async onLoad () {
      // 1. 请求获取数据
      const { data } = await getComments({
        type: this.type, // 评论类型,a-对文章(article)的评论,c-对评论(comment)的回复
        source: this.source.toString(), // 源id,文章id或评论id
        offset: this.offset, // 获取评论数据的偏移量,值为评论id,表示从此id的数据向后取,不传表示从第一页开始读取数据
        limit: 10 // 每页大小
      })


      // 2. 将数据添加到列表中
      const { results } = data.data
      this.list.push(...results)
      // // 更新总数据条数
      // this.totalCount = data.data.total_count
     this.$emit('onload-success', data.data.total_count)

      // 3. 将加载更多的 loading 设置为 false
      this.loading = false

      // 4. 判断是否还有数据
      if (results.length) {
        this.offset = data.data.last_id // 更新获取下一页数据的页码
      } else {
        this.finished = true // 没有数据了,关闭加载更多
      }
    },
  • 评论点赞功能逻辑:利用liking属性和com_id通过调用评论点赞接口,如果未点赞就调用点赞接口,如果已经点赞就调用取消点赞接口
 // 评论点赞功能
      async onCommentLike (comment) {
      // 如果已经赞了则取消点赞
  if (comment.is_liking) {
    await deleteCommentLike(comment.com_id)
  } else {
    // 如果没有赞,则点赞
    await addCommentLike(comment.com_id)
  }

  // 更新视图状态
  comment.is_liking = !comment.is_liking
  this.$toast('操作成功')
},

发布文章评论功能

  • 调接口注意点:这里对文章发表评论的接口,需要传入当前文章的id,和评论内容
  • 功能逻辑:当点击发表评论按钮时会有输入框弹窗,在弹窗中输入的内容会同步渲染到评论列表中
  • 功能技术点:使用了vant的弹窗组件,这里把弹出的的输入框也封装成了组件插入到弹窗组件中,在组件中调用发布评论的接口传入对应参数,然后使用子传父的方法定义一个事件,将获取到的内容对象传给父组件,在父组件的数组中追加,完成视图的更新
  async onAddComment () {
  const inputComment = this.inputComment.trim()
// 非空校验
  if (!inputComment.length) {
    return ;
  }
 // 请求添加
  const res = await addComment({
    target: this.target.toString() , // 评论的目标id(评论文章即为文章id,对评论进行回复则为评论id)
    content: inputComment, // 评论内容
     art_id:this.articleId?this.articleId.toString():null // 文章id,对评论内容发表回复时,需要传递此参数,表明所属文章id。对文章进行评论,不要传此参数。
  })
  this.inputComment = ''
  // 传给父组件更新视图
  this.$emit('onpost-success', res)
}

回复评论功能

  • 功能逻辑:当点击评论中的回复按钮时需要有新的弹窗,里面会显示当前评论的内容和下面对这条评论的回复,这里我也是在文章详情的页面中定义的弹出层,不过在评论列表组件中使用了子传父技术,当点击回复按钮时把当前评论的对象传递给文章详情页面,在文章详情页面中监听自定义事件,弹出窗口,接收评论对象
  • 定义回复评论弹窗:同样适用vant中的弹窗组件,把回复评论的页面封装成组件,插入到弹窗中
  • 功能技术点:在评论列表组件中使用子传父技术,将对象传给父组件,在父组件中定义变量接收参数,监听事件,在事件中设置弹窗变量为true,弹出弹窗,然后在接收参数,把接收到的参数通过父传子的方式再传给回复评论组件
 <van-button size="mini" type="default"
             @click="$emit('click-reply',item)"
            >回复{{item.reply_count}}</van-button>
            
  
  //点击显示回复弹窗事件
  onReplyShow(comment){
    this.isReplyShow=true
    this.comment = comment
  } 
  • 搭建弹窗页面:使用vant的cell单元格搭建当前评论的内容,用拿到的参数渲染页面
  • 回复评论逻辑:这里还是调用了原来封装好的评论列表和发布评论的组件,完成功能,这里在监听事件时同时对头部的回复数量做了处理,每当发表新的回复就让参数++可以让数据保持更新
  • 功能问题点:这里忽略了在对评论回复时需要传入评论id而传入了文章id导致页面一直渲染不上
  • 功能问题点:这里在调用封装好的组件时出现了接口401的报错,原因是因为回复评论需要传的评论id过长,axios会自动转成字符串所以多了引号导致格式不对,这里需要手动对传入的评论id做toString()的转化处理操作
<template>
 <div>
     <!-- 导航栏 -->
    <van-nav-bar :title="comment.reply_count + '条回复'">
    <van-icon slot="left" name="cross"  @click="$emit('closePop')" />
    </van-nav-bar>
<!-- /导航栏 -->

<!-- 当前评论 -->
<van-cell title="当前评论">
  <van-image
    slot="icon"
    round
    width="30"
    height="30"
    style="margin-right: 10px;"
    :src="comment.aut_photo"
  />
  <span style="color: #466b9d;" slot="title">{{ comment.aut_name }}</span>
  <div slot="label">
    
    <p style="color: #363636;">{{ comment.content }}</p>
    <p>
      
      <span style="margin-right: 10px;"
        >{{ comment.pubdate | relativeTime }}</span
      >
      <van-button size="mini" type="default" 
      @click="isPostShow=true"
        >回复 {{ comment.reply_count }}</van-button
      >
    </p>
  </div>
  <van-icon slot="right-icon" />
</van-cell>
<!-- /当前评论 -->
<van-cell>全部评论</van-cell>
<!-- 评论列表 -->
    <commentItem
    :list="backlist"
    :source="comment.com_id"
    type="c"
    ></commentItem>
    <!-- 评论列表 -->


     <!-- 发表评论弹窗组件 -->
     <van-popup
          v-model="isPostShow"
          position="bottom"
        >
       <postComment
       @onpost-success="onPostSuccess"
       :target="comment.com_id"
       ></postComment>
        <!-- 发表评论弹窗组件 -->
        </van-popup>
 </div>
</template>

<script>
import commentItem from '@/components/article-comment/article-comment.vue'
import postComment from '@/components/post-comment/post-comment.vue'
export default {
    name:'commentBack',
    components:{
    commentItem,
    postComment
    },
    created(){
        console.log(this.comment);
    },
props: {
  comment: {
    type: Object,
    required: true
  },
},
data(){
    return{
        isPostShow:false,
        backlist:[]
    }
},
methods:{
    onPostSuccess(res){
      this.comment.reply_count = this.backlist.length
      this.comment.reply_count++
      this.backlist.unshift(res.data.data.new_obj)
      this.$toast.success('评论成功')
      this.isPostShow = false
},
}
}
</script>

<style>

</style>