【项目实战】基于Vue3+Vant3造一个网页版的类掘金app项目 - 评论块组件封装

876 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

前言

大家好,今天继续来分享我们到掘金项目实战系列的沸点评论功能。在昨天的分享中我们实现了沸点最新的5条评论的展示功能。今天的分享中我们将不实现新功能,而是把昨天的代码进行一下简单的优化 - 将评论块抽取出来封装成通用的插件,以实现代码的复用。

评论区块分析

如下图我们先来分析下面评论区块的模样。 image.png 我们可以看到不管是评论还是子评论基本长相都是一样的,都是由用户基本信息、评论内容、点赞和回复几个模块组成,并且跟主沸点的结构也很相似,虽然我们可以用vue中的v-for指令将其循环输出,但是仍然会造成代码的冗余,比如同一套代码(标签样式都相同)可能会在三个地方用到(主沸点内容模块,评论内容和子评论中),而事实上我们现在项目中的代码也是这么写的(如下图),因此我们需要将冗余代码抽取出来封装成通用组件以提高代码的复用 image.png

组件功能分析

首先我们将上图中的“author”和“content”模块进行抽取封装,在将这两段代码展开后会包含如下信息:作者头像,昵称等基本信息,沸点或评论内容信息,以及如果内容超长还会有“展开”和“收起”两个蓝色按钮以及对应的两个展开和收起行为的js方法,最后如果内容涉及图片还会有用于显示图片的标签信息,既然要封装成通用组件,那么这些信息就需要做成动态,我们可以将其定义为组件的props,然后在父组件中作为参数传进去。思路已经清晰,下面就可以动手开撸了:

  • 在views中新增一个comment.vue组件
  • 将author和content中的代码抽取出来拷贝到comment.vue中
  • 将对应到样式及js方法一同拷贝到comment.vue中
  • 将author和content中对应要渲染的内容定义成props,可视情况进行增减
  • 最后再在Fire.vue中导入comment.vue组件替换在沸点内容区,评论区和子评论区 核心代码及最终效果图:
<!--父组件 Fire.vue-->
<comment
    :avatar_large="msg.author_user_info.avatar_large"
    :user_name="msg.author_user_info.user_name"
    :job_title="msg.author_user_info.job_title"
    :company="msg.author_user_info.company"
    :ctime="msg.msg_Info.ctime"
    :origin_content="msg.msg_Info.content"
    :sub_content="msg.msg_Info.sub_content"
    :comment_id="msg.msg_Info.msg_id"
    :pic_list="msg.msg_Info.pic_list"
    @showImage="showImage
    />
<!--子组件 comment.vue-->
<template>
  <div class="author">
    <van-image class="photo" round :src="avatar_large" />
    <div style="display: flex; flex-direction: column">
      <div class="author-title">
        {{ user_name }}
      </div>
      <div class="pub-time">
        {{ job_title }} @ {{ company }} ·
        {{ publishTime(ctime) }}
      </div>
    </div>
  </div>
  <div class="content">
    <div style="overflow: hidden; line-height: 20px">
      <span style="white-space: pre-line"> {{ content }}</span>
      <div
        class="limit-btn"
        v-if="origin_content.length >= 80 && content.length <= 83"
        @click="showFullContent(comment_id)"
      >
        展开
      </div>
      <div
        class="limit-btn"
        v-if="origin_content.length >= 80 && content.length > 83"
        @click="hideFullContent(comment_id)"
      >
        收起
      </div>
    </div>

    <van-image
      :src="pic"
      v-for="(pic, $index) in pic_list"
      :key="$index"
      class="image"
      @click="showImage(pic)"
    />
  </div>
</template>
import { reactive, toRefs } from "vue";
import utils from "../utils/utils";
export default {
  name: "comment",
  props: {
    avatar_large: {
      type: String,
      required: true,
    },
    user_name: {
      type: String,
      required: true,
    },
    job_title: String,
    company: String,
    ctime: {
      type: String,
      required: true,
    },
    sub_content: {
      type: String,
      required: true,
    },
    origin_content: {
      type: String,
      required: true,
    },
    comment_id: {
      type: String,
      required: true,
    },
    pic_list: {
      type: Array,
    },
  },
  components: {},
  setup(props, ctx) {
    const { sub_content, origin_content } = props;
    const state = reactive({ content: sub_content });
    const publishTime = utils.getPublishTime;

    const showFullContent = function (msg_id) {
      state.content = origin_content;      
    };

    const hideFullContent = function (msg_id) {
      state.content = sub_content;   
    };

    const showImage = (imgUrl) => {
      ctx.emit("showImage", imgUrl);
    };

    return {
      ...toRefs(state),
      publishTime,
      showFullContent,
      hideFullContent,
      showImage,
    };
  },
};

改造完成之后我们再来预览一下效果图,各个区块的内容都能正常展示出来,好像跟之前也没什么变化,这就说明我们此次的封装是正确没有问题的。 test.gif

总结

今天的分享中我们对沸点内容,评论及子评论区块进行来抽取封装,减少了冗余代码实现了代码复用,虽然在Fire.vue中代码还是一大坨,但对于改善代码质量来说也算是一点点进步。此次的分享就到这里了,喜欢的小伙伴欢迎点赞留言加关注。