头条案例day08:

评论点赞:

封装请求,给评论项中的like图标注册点击事件,在事件中处理。
判断是否登录,已登录再判断是否点赞,有,取消点赞,没有,点赞。未登录,提示请登录。

// 点赞或取消点赞事件
async onCommentLike () {
  // loading 开启  
  this.commentLoading = true
  try{
       // 如果已经赞了则取消点赞
      if (this.comment.is_liking) {
        await deleteCommentLike(this.comment.com_id)
        this.comment.like_count--  
      } else {
        // 如果没有赞,则点赞
        await addCommentLike(this.comment.com_id)
        this.comment.like_count++
      }
      // 更新视图状态
      this.comment.is_liking = !this.comment.is_liking
      this.$toast('操作成功')
  }catch(e){
      this.$toast('操作失败,请重试')
  }
  // loading 关闭
  this.commentLoading = false  
}


发表文章评论:

1. 准备弹出层:

使用vant组件进行铺设

<van-popup v-model="isPostShow" position="bottom">
    测试内容
</van-popup>

绑定事件打开弹出层,不设置高度,内容会自动撑开弹层高度

<van-button
    class="comment-btn"
    type="default"
    round
    size="small"
    @click="isPostShow=true"   
    >写评论</van-button>

2. 封装组件:components/comment-post.vue组件,弹出层中引入

<van-popup v-model="isPostShow"  position="bottom">
    <comment-post />
</van-popup>

3. 请求发布:
基本思路:

- 找到数据接口
- 封装请求方法
- 注册发布点击事件
  - 请求发布
  - 成功:将发布的内容展示到列表中
  - 失败:提示失败

父子通信,传递文章id:

父:article/index.vue
<van-popup v-model="isPostShow" position="bottom">
    <comment-post :target="article.art_id" />
</van-popup>

子:comment-post.vue

 props: {
    // 目标id,接收文章id或者评论id   
    target: {
      type: [Number, String, Object],
      required: true
    }
  }

comment-post.vue导入请求方法、绑定事件、书写事件函数、发送请求

    async onPost () {
      this.$toast.loading({
        message: '发布中...',
        forbidClick: true, // 禁用背景点击
        duration: 0 // 持续时间,默认 2000,0 表示持续展示不关闭
      })

      try {
        const { data } = await addComment({
          target: this.target.toString(), // 评论目标id(评论文章即文章id,对评论进行回复则为评论id) 防止有大数字最好也执行一下toString方法!
          content: this.message, // 评论内容
          art_id: null // 文章id,对评论内容发表回复时,需要传递此参数,表明所属文章id。对文章进行评论,不要传此参数。
        })
        
        this.$toast.success('发布成功')
        
         // TODO==>
            // 关闭弹出层
            // 将发布内容显示到列表顶部
            // 清空文本框
      } catch (err) {
        this.$toast.fail('发布失败')
      }
    }

4. 成功处理:
核心要点
- 清空文本框:
子组件`comment-post.vue`中清除`message`内容,通过自定义事件向外抛出 添加成功的数据
- 关闭弹出层:
父组件`article/index.vue` 中监听`post-success`自定义事件,执行关闭弹层和将数据放入顶部的操作
- 将发布内容显示到列表顶部

【父子通信的`props` 如果是一个 数组,我们只要不重新赋值这个`props`里面的数组,就都不算修改`props`,而可以实现父子之间共享数据,实时变化。(其本质是父子用了一个引用数据类型的数据)】
5. 空内容处理:
对输入的内容进行去除空格处理,增加`trim` 修饰符
内容没有输入的时候我们禁用 按钮

评论回复:

1. 准备回复弹层

在详情页中使用弹层用来展示文章的回复
1、在`article/index.vue` 中`data`添加数据用来控制展示回复弹层的显示状态

data () {
  return {
    // 其他变量...
    isReplyShow: false
  }
}

2、在详情页`article/index.vue`中添加使用弹层组件

<van-popup
  v-model="isReplyShow"
  position="bottom"
  style="height: 100%"
>
  评论回复
</van-popup>

2. 点击回复显示弹出层

`comment-item.vue`组件里面给回复按钮绑定事件,触发向外传递点击行数据(自定义事件)

<van-button
          class="reply-btn"
          round
          @click="$emit('reply-click', comment)" 
 >回复 {{ comment.reply_count }}</van-button>

父组件`comment-list.vue`监听自定义事件,继续向外传递收到的数据(自定义事件)

<comment-item
      v-for="(item, index) in list"
      :key="index"
      :comment="item"
      @reply-click="$emit('reply-click', $event)" 
    />

爷爷组件`article/index.vue` 监听自定事件,打开弹框,输出收到的数据

<comment-list
   :source="article.art_id"
   :list="commentList"
   @onload-success="totalCommentCount = $event.total_count"
   @reply-click="onReplyClick" 
/>

onReplyClick (comment) {
   console.log(comment) // comment-item组件传递出来的数据
   // 显示评论回复弹出层
   this.isReplyShow = true
}

3. 封装内容组件

创建components/comment-reply.vue`组件

4. 传递当前点击回复的评论项

思路:回顾4.2节,我们已经在`article/index.vue`中得到了`comment-item.vue`里面回复按钮传递出来的数据,我们定义变量接收,然后通过父子通信传递给`comment-reply.vue`组件

5. 处理头部及当前评论项

`comment-reply.vue` 布局内容,绑定数据
父组件`article/index.vue`中监听关闭事件

6. 展示评论回复列表

基本思路:- 回复列表和文章的评论列表几乎是一样的,所以我们复用`comment-list.vue`组件
- 修改 `comment-list.vue ` 组件,因为既要让他满足文章列表要求又要满足评论列表要求

1、修改`comment-list.vue`组件

props: {
    // 文章id或者评论id===> 此刻 接收的是评论id
    source: {
      type: [Number, String, Object],
      required: true
    },
    // 用于和父组件共享数据,实现添加评论列表更新,插入    
    list: {
      type: Array,
      default: () => []
    },
    // 【新增这个type】判断是文章还是评论    
    type: {
      type: String,
      // 自定义 Prop 数据验证
      validator (value) {
        return ['a', 'c'].includes(value)
      },
      default: 'a'
    }
}

async onLoad(){
    // 很多代码...
    
    // 获取文章的评论和获取评论的回复是同一个接口
    // 唯一的区别是接口参数不一样
    //    type
    //      a 文章的评论
    //      c 评论的回复
    //    source
    //      文章的评论,则传递文章的 ID
    //      评论的回复,则传递评论的 ID
    // 1. 请求获取数据
    const { data } = await getComments({
        type: this.type, //  评论类型,a-对文章(article)的评论,c-对评论(comment)的回复
        source: this.source.toString(), // 源id,文章id或评论id  【文章id或者评论id都有可能存在大数字】
        offset: this.offset, // 获取评论数据的偏移量,值为评论id,表示从此id的数据向后取,不传表示从第一页开始读取数据
        limit: this.limit // 获取的评论数据个数,不传表示采用后端服务设定的默认每页数据量
    })
    
    // 很多代码...
}

2、在`comment-reply.vue`中导入`comment-list.vue`,注册,使用

7. 回复列表数据重复数据问题

原因: `van-list` 组件有个特点,就是只有在可视范围内才会自动调用`load`事件,所以我们之前文章内容过长,就不会触发请求文章评论列表,故而 我们手动在`created`里面调用了`onLoad`方法,但是现在我们这里的回复列表一开始就在可是范围内,故而会触发2次请求,1次是可视范围内自动触发,1次是我们主动调用触发。所以我们要关闭 自动检测可视范围自动调用。

8. 回复列表内容不更新问题

弹层组件:- 如果初始的条件是 false,则弹层的内容不会渲染
- 程序运行期间,当条件变为 true 的时候,弹层才渲染了内容
- 之后切换弹层的展示,弹层只是通过 CSS 控制隐藏和显示

原因: 弹层渲染出来以后就只是简单的切换显示和隐藏,里面的内容也不再重新渲染了,所以会导致我们的评论的回复列表不会动态更新了。解决办法就是在每次弹层显示的时候重新渲染组件。

<!--弹出层是懒渲染的:只有在第一次展示的时候才会渲染里面的内容,之后它的关闭和显示都是在切换内容的显示和隐藏-->
<van-popup v-model="isReplyShow"position="bottom"  style="height: 100%;">
    <!--
            v-if 条件渲染
            true:渲染元素节点
            false:不渲染
    -->
    <comment-reply
        v-if="isReplyShow"   
        :comment="currentComment"
        @close="isReplyShow = false"
     />
</van-popup>

9. 发布回复

处理底部视图 `comment-reply.vue`
处理参数
评论回复接口的时候我们发现`comment-post.vue`不仅需要评论id,还需要文章的对应id,这个时候 我们父组件`comment-reply.vue`并没有, 而 `article/index.vue` 组件是有的,这个时候就需要有一个祖先后代通信过程(不选择多层父子的原因是因为比较复杂)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值