封装你的第一个vue组件

本文讲述了新入职的阿花在A公司遇到的首个任务——使用ElementUI实现具备多种功能的表格。在同事乔木的指导下,阿花了解到组件封装的重要性,以减少代码冗余和提高复用性。通过组件化,阿花实现了包含固定列、标签列、内容操作等功能的表格,并学会了如何根据业务需求调整组件内容。最后,阿花成功地将表格封装为一个可复用的Vue组件。
摘要由CSDN通过智能技术生成

故事背景:

结束了四年的大学生活,阿花成功信心满满的投递出自己的简历,最终加入了A公司成为A公司的一员。

今天是阿花第一天入职,在简单熟悉了一下项目代码后,项目经理给阿花分了一个利用Element UI 实现一个支持固定列、标签列、内容超出省略、内容操作等功能的表格

整体ui展示图例

在这里插入图片描述

一、表格功能实现

阿花接到需求后,当即利用Element UI着手实现了完整功能的table组件

<template>
  <div>
    <el-table
    v-if="tableData.length != 0"
    :data="tableData"
    border
    stripe
    class="active_table"
    style="width:100%">
    <el-table-column
      fixed
      prop="active_name"
      label="活动名称"
      width="100">
    </el-table-column>
    <el-table-column
      prop="active_duty"
      label="活动负责人"
      width="100">
    </el-table-column>
    <el-table-column
      prop="club_name"
      label="申请社团"
      width="100">
    </el-table-column>
    <el-table-column
      prop="active_tem"
      label="负责人联系方式"
      width="100">
    </el-table-column>
    <el-table-column
      prop="active_date"
      label="活动时间"
      width="100">
    </el-table-column>
    <el-table-column
      prop="active_region"
      label="活动地点"
      width="100">
    </el-table-column>
    <el-table-column
      prop="active_num"
      label="活动人数"
      width="100">
    </el-table-column>
    <el-table-column
      prop="state"
      label="活动状态"
      width="100">
      <template slot-scope="scope">
        <el-tag
          :type="judge(scope.row.state)"
          disable-transitions>{{scope.row.state}}</el-tag>
      </template>
    </el-table-column>
    <el-table-column
      prop="active_desc"
      show-overflow-tooltip	
      label="活动简介"
      width="300">
    </el-table-column>
    <el-table-column
      fixed="right"
      label="操作"
      width="80">
      <template slot-scope="scope">
        <el-button @click="handleActive(scope.row.id)" type="text" size="small">查看详情</el-button>
      </template>
    </el-table-column>
  </el-table>
  <el-empty description="暂无活动申请" v-else></el-empty>
  </div>


</template>

<script>
  export default {
    methods: {
      handleActive(id) {
         this.$router.push({ name: 'CheckActive', params: { id: id }})
      },
      // 初始化
      loadActiveApply () {
        this.$api.active
        .findAllActives(this.$store.state.userStore.userType)
        .then((result) => {
            if (result.msg == "ok") {
              for(let item in result.data){
                result.data[item].active_date = result.data[item].active_date.split("T")[0]
              }
              this.tableData = result.data
            }
        })
      },
      judge(state){
        if(state == '审核通过'){
          return 'success'
        }else if(state == '审核不通过'){
          return 'danger'
        }else {
          return 'paimary'
        }
      }
    },
    mounted(){
      this.loadActiveApply()
    },
    data() {
      return {
        tableData: []
      }
    }
  }

于是准备着手将代码提交到代码仓库,这时一位同事乔木看到阿花准备提交的代码,摇摇头说:“阿花,稍等一下,先不要提交”

“怎么了?”

“你为什么不把这个表格封装成一个组件呢”

“需求上的功能我已经实现了阿”

“假如之后再需要使用类似的table表格你每次都重新再写一份吗?这样代码太冗余了”

阿花瞬间不知所措起来,乔木说的有道理,但是封装组件他并不是很熟悉。。。。

组件封装的优势

乔木见状连忙拍拍阿花的肩膀笑道:“那我给你讲讲在项目开发中组件封装的优越性吧”

乔木道: “ 我们把⼀个功能的模板(template)封装 在⼀个.vue 文件中。把每个组件的逻辑和样式,也就是把HTML、JavaScript 和 CSS 封装在⼀起,这样在项目中任何地方都可以再次复用整个组件的代码,减少代码冗余”

“ 可是,我这个代码的.vue文件如果其他地方需要复用,引入不也是可以的吗…”

“是的,你上面写出的代码在功能上没有问题,在需求完全一致时也能复用,但是如果新的需求时不需要表格中有标签列或者列定位呢?”

“ 那,那可能需要重新写功能匹配的表格代码了 ”

“ 所以你就需要将其封装成一个组件,根据业务需求对组件进行定制 ”

功能拆分

“ 可是我该怎么做呢?” 阿花迫不及待的问道

“ 那我就简单的给你分析一下怎么进行组件封装 ”

“ 既然要根据业务需求对组件进行定制,那么在实现所有功能之后,肯定是将不同业务对应的功能抽离出来 ”

实现上面的表格需求我们可以将单元格拆分为 :
① 常规列
② 溢出省略功能列
③ 标签功能列
④ 左表格固定列
⑤ 表格内容操作列

“ 然后根据不同的需求展示不同列中的内容,那你知道怎么实现单元格内容按需求展示吗? ”

“ v-if,v-if 可以条件性地渲染一块内容,判断指令返回truthy值时进行渲染。

数据传递

“ 是的,但是指令和渲染的数据从哪里来呢? ”

“ 当然是从父组件那里传过去了,父组件根据需求给子组件传递对应的数据,子组件对收到的数据进行个性化展示。 ”,阿花激动道

“ 那我考考你,你还记得父子组件之间传递数据有什么方法吗? ” ,乔木问

“ 记得记得 ,父传子用prop、子传父用emit、多组件共享数据用全局事件总线、消息的订阅与发布、vuex状态管理库”

“ 是的,那这种情况下我们使用什么方法传递数据比较合适? ”

“ prop,组件的封装然后复用 数据流是父 ==> 子,在子组件指定接收的验证需求,然后父组件传递符合验证需求的数据 ”

“ 没错,如果需要父子组件交互还会使用到emit自定义事件,但是我们这个需求不需要了,那现在你看看能不能优化一下你上面的代码 ”

于是阿花拍了一下脑袋,在乔木的指教下写出了如下代码

子组件

<template>
  <div>
    <el-table
      :v-loading="loading"
      v-if="tableData.length != 0"
      :data="tableData"
      border
      stripe
      class="active_table"
      style="width: 100%"
      max-height="600"
    >
      <!-- 左侧固定列名 -->
      <el-table-column
        v-if="fixedLeft"
        :prop="fixedLeftName"
        :label="fixedLeftLable"
        fixed
        min-width="100"
      ></el-table-column>
      <!-- 正常列 -->
      <el-table-column
        v-for="(value, name) in lableObject"
        :key="name"
        :prop="name"
        :label="value"
        fit="true"
        min-width="100"
      ></el-table-column>
      <!-- 标签列 -->
      <el-table-column v-if="tableTag" :prop="tagName" :label="tagLable" min-width="100" >
        <template slot-scope="scope">
          <el-tag :type="judge(scope.row[tagName])" disable-transitions>
            {{ scope.row[tagName] }}
          </el-tag>
        </template>
      </el-table-column>

      <!-- 超出省略列 -->
      <el-table-column
        v-if="overflowTooltip"
        :prop="overflowTooltipName"
        :label="overflowTooltipLable"
        :width="overflowTooltipWidth"
        show-overflow-tooltip
      ></el-table-column>

      <!-- 操作表格列 -->
      <el-table-column v-if="operateTable" fixed="right" :label="operateTable.lable" min-width="100">
        <template slot-scope="scope">
          <el-button @click="handleActive(scope.row.id)" type="text" size="small"
            >{{operateTable.value}}</el-button
          >
        </template>
      </el-table-column>

    </el-table>
    <el-empty :description="emptyTable" v-else></el-empty>
  </div>
</template>

<script>
export default {
  props: {
    // 常规表格数据
    tableData: {
      type: Array,
      required: true,
    },
    // 表格数据对应的lable
    lableObject: {
      type: Object,
      required: true,
    },
    // 有表格操作时使用
    operateTable: {
      type: Object,
    },
    // 数据为空时展示的结果
    emptyTable: {
      type: String,
      default: "数据为空",
    },
    // 溢出省略列
    overflowTooltip: {
      type: Object,
    },
    // 左定位列
    fixedLeft: {
      type: Object,
    },
    // 标签列
    tableTag: {
      type: Object,
    }
  },
  methods: {
    judge(state) {
      if (state == `${this.tableTag.success}`) {
        return "success";
      } else if (state == `${this.tableTag.danger}`) {
        return "danger";
      } else {
        return "paimary";
      }
    },
    handleActive(id) {
      this.$router.push({ name: this.operateTable.url, params: { id: id }})
      this.loading = !this.loading
    },
    loadTable() {
      // 初始化标签列
      if(this.tableTag){
        this.tagName = Object.keys(this.tableTag)[0];
        this.tagLable = this.tableTag[this.tagName];
      }
      // 初始化fixed定位列
      if(this.fixedLeft){
        this.fixedLeftName = Object.keys(this.fixedLeft)[0];
        this.fixedLeftLable = this.fixedLeft[this.fixedLeftName];
      }
      // 初始化省略行列
      if(this.overflowTooltip){
          this.overflowTooltipName = Object.keys(this.overflowTooltip)[0];
          this.overflowTooltipLable = this.overflowTooltip[this.overflowTooltipName];
          this.overflowTooltipWidth = this.overflowTooltip.width
      }
    }
  },
  data() {
    return {
      tagName: "",
      tagLable: "",
      fixedLeftName: "",
      fixedLeftLable: "",
      overflowTooltipName:'',
      overflowTooltipLable:'',
      overflowTooltipWidth: '',
      loading: true
    }
  },
  mounted() {
    this.loadTable()
  }
};
</script>

父组件

<template>
  <div>
    <v-Table
      :tableData="tableData"
      :lableObject="lableObject"
      :operateTable="operateTable"
      :tableTag="tableTag"
      :fixedLeft="fixedLeft"
      :overflowTooltip="overflowTooltip"
      emptyTable="暂无活动申请"
    ></v-Table>
  </div>
</template>

<script>
import vTable from "@/components/vTable.vue";

export default {
  components: {
    vTable,
  },
  methods: {
  // 从后端获取表格信息的ajax请求
    loadActiveApply() {
      this.$api.active
        .findAllActives()
        .then((result) => {
          if (result.msg == "ok") {
            this.tableData = result.data;
          }
        });
    },
  },
  mounted() {
    this.loadActiveApply();
  },
  data() {
    return {
      tableData: [],
      // 表数据是通过后端返回的,如果返回的格式中lable和value的对应关系明确则 不需要lableObject的定义
      // 表数据(key)和表头(value)对应关系
      lableObject: {
        active_duty: "活动负责人",
        club_name: "申请社团",
        active_tem: "联系方式",
        active_date: "活动时间",
        active_region: "活动地点",
        active_num: "活动人数",
      },
      // 标签列的表头和标签状态
      tableTag: {
        state: "活动状态",
        success: "审核通过",
        danger: "审核不通过"
      },
      // 左fixed的列
      fixedLeft: {
        active_name: "活动名称",
      },
      // 溢出省略的列
      overflowTooltip: {
        active_desc: "活动简介",
        width: '300'
      },
      // 可以跳转的列
      operateTable: {
        lable: "操作",
        value: "查看详情",
        // 跳转路径
        url: 'CheckActive'
      },

    };
  },
};
</script>

自此阿花的第一个组件封装算是基本完成了,接下来他的求职路上又会出现什么问题呢,让我们拭目以待吧。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值