Vue业务组件封装Table表格示例详解

目录
  • 前言
  • Table组件介绍
  • Table组件封装思路
    • 了解element Table组件代码
  • Table组件如何去封装
    • 新建LTable组件
    • 配置文件
    • 配置插槽
  • 动态组件
    • 解决插槽存在的问题
    • 代码实现
  • 总结

前言

这个系列主要是分享自己在工作中常用到的业务组件,以及如何对这些组件进行有效的封装和封装的思路。注:都是基于element ui进行二次封装。

封装组件的基本方法就是通过props和emit进行父子组件的传值和通信。利用插槽、组件等去增加组件的可扩展性和复用性。

Table组件介绍

用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。table组件常用于后台管理系统,基本上是后台管理系统中使用频率最高的组件了,一个table组件具有最基本的功能就是crud。

基本的table

Table组件封装思路

了解element Table组件代码

这里以最基本的Table代码为例进行分析:

 <template>
  <el-table
    :data="tableData"
    style="width: 100%">
    <el-table-column
      prop="date"
      label="日期"
      width="180">
    </el-table-column>
    <el-table-column
      prop="name"
      label="姓名"
      width="180">
    </el-table-column>
    <el-table-column
      prop="address"
      label="地址">
    </el-table-column>
  </el-table>
</template>
<script>
  export default {
    data() {
      return {
        tableData: [{
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        }, {
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1517 弄'
        }, {
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1519 弄'
        }, {
          date: '2016-05-03',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1516 弄'
        }]
      }
    }
  }
</script>

table样式

根据基本的Table代码,我们可以知道:

  • Table渲染的数据是一个数组,数组的每一项包含了每一列的信息,然后绑定到el-table的data属性里面。
  • el-table-column为Table一行中每列的内容,一行有多少列,就写多少个el-table-column。
  • 每个el-table-column中绑定了prop、label属性,他们分别对应data数据里所渲染出来的内容和每列的表头文字,注意prop的值一定要与tableData里的对象属性相同。

Table组件如何去封装

通过分析Table代码我们可以把el-table-column里面绑定的属性抽离出一个配置文件,通过对配置文件的遍历得到所有el-table-column。

配置文件代码实现

新建LTable组件

我们在components文件夹下新建一个LTable表示我们封装的Table组件。基于Table组件的基本代码,我们写下LTable下代码内容:

<template>
  <div>
    <el-table :data="tableData" border style="width: 100%">
      <el-table-column type="index" align="center" width="50" v-if="showIndexColumn">
      </el-table-column>
      <el-table-column type="selection" align="center" width="55" v-if="showSelectColumn">
      </el-table-column>
      <template v-for="item in columnList">
        <el-table-column :key="item.prop" align="center" v-bind="item">
        </el-table-column>
      </template>
    </el-table>
  </div>
</template>
<script>
export default {
  props: {
    columnList: {
      type: Array,
      default: () => []
    },
    showIndexColumn: {
      type: Boolean,
      default: false
    },
    showSelectColumn: {
      type: Boolean,
      default: false
    },
    requestUrl: {
      type: String,
      require: true
    }
  },
  created() {
    this.getData();
  },
  data() {
    return {
      tableData: [],
      // defaultSlotList: ["action"]
    };
  },
  computed: {
    isDefaultSlot() {
      return function(slotName) {
        return this.defaultSlotList.includes(slotName);
      };
    }
  },
  methods: {
    getData() {
      this.api.get(this.requestUrl).then(res => {
        this.tableData = res.dataList
      })
    },
    // handleEdit(row) {
    //   console.log(row);
    // },
    // handleDelete(row) {
    //   console.log(row);
    // }
  }
};
</script>

在组件中我们需要父组件传入一个columnList,也就是前面我们说的配置文件,table的数据我们在LTable里获取,不用父组件传递过来。这样做的好处是:将通过接口获取table数据统一在LTable管理,减少父组件获取接口数据然后传递给LTable的重复代码逻辑。相应我们需要传递请求数据的接口地址。

配置文件

新建一个配置文件tableConfig.js,导出文件内容,然后再需要用到的页面引入。

export const tableConfig = {
  columnList: [
    {
      label: "日期",
      prop: "date",
      sortable: true //对表格进行排序
    },
    {
      label: "图片", //文字
      prop: "imgSrc", //渲染数据对应的属性
      width: "180" //每列对应宽度
    },
    {
      label: "姓名",
      prop: "name"
    },
    {
      label: "地址",
      prop: "address"
    }
  ],
  showIndexColumn: true, //是否显示table索引
  showSelectColumn: true, //是否显示选择多行
  requestUrl: "api/getData" //接口请求地址
};

页面内容:

<template>
  <div class="app-container">
    <l-table v-bind="tableConfig"></l-table>
  </div>
</template>
<script>
import { tableConfig } from "./config/tableConfig.js";
export default {
  components: { LTable: () => import("@/components/LTable") },
  data() {
    return {
      tableConfig
    };
  },
  mounted() {},
  methods: {}
};
</script>

table效果

这样,一个基本的Table封装就完成了,可以看到我们在页面中的代码是非常少的,只有引入了组件,然后将配置文件绑定到组件上就可以了。

不过目前写的配置都是非常简单的,如果遇到复杂的表格内容,我们怎么办?

配置插槽

刚刚完成的小案例我们发现图片是直接显示了地址,那我们想展示图片怎么办,一般表格还会有操作列,我们怎么展示出来呢?

这种我们不能直接渲染数据,而是需要转换,比较灵活得到我们想要的的内容就需要用到插槽了。

首先我们需要在配置文件增加插槽的选项,我们这里取名slotName:

columnList: [
  {
    label: "日期",
    prop: "date",
    Sortable: true
  },
  {
    label: "图片",
    prop: "imgSrc",
    width: "180",
    slotName: "img"
  },
  {
    label: "姓名",
    prop: "name"
  },
  {
    label: "地址",
    prop: "address"
  },
  {
    label: "操作",
    prop: "action",
    slotName: "action"
  }
],

对应的LTable组件里面的渲染逻辑我们也需要调整,改为有插槽和没有插槽两种情况去渲染。表格里的插槽有些在所有表格里面都会用到比如操作,这种我们就当做默认插槽,写在LTabl里面。

不是每个表格都需要用到插槽就是动态插槽了,放在对应的页面里。

LTable增加插槽的代码:

<template>
  <div>
    <el-table :data="tableData" border style="width: 100%">
      // 带有索引列
      <el-table-column type="index" align="center" width="50" v-if="showIndexColumn">
      </el-table-column>
      // 多选列
      <el-table-column type="selection" align="center" width="55" v-if="showSelectColumn">
      </el-table-column>
      <template v-for="item in columnList">
        <el-table-column :key="item.prop" v-if="item.slotName" v-bind='item' align="center">
          <template slot-scope="scope">
            <!-- 动态插槽 -->
            <slot v-if="!isDefaultSlot(item.slotName)" :name="item.slotName"
              :row="scope.row">
            </slot>
            <!-- 默认插槽 -->
            <slot v-else name="action">
              <el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button>
              <el-button size="mini" type="danger" @click="handleDelete(scope.row)">删除</el-button>
            </slot>
          </template>
        </el-table-column>
        // 直接渲染列
        <el-table-column v-else :key="item.prop" align="center" v-bind='item'>
        </el-table-column>
      </template>
    </el-table>
  </div>
</template>

页面里面动态插槽内容:

<template>
  <div class="app-container">
    <l-table v-bind="tableConfig">
      <template #img="scope">
        <el-image
          style="width: 100px; height: 100px"
          :src="scope.row.imgSrc"
          :preview-src-list="[scope.row.imgSrc]"
          fit="cover"
          preview-teleported
        ></el-image>
      </template>
    </l-table>
  </div>
</template>

渲染出来的表格:

带有插槽表格

这样,我们就通过配置文件搭配插槽完成了Table组件的封装,我们可以自由灵活的显示我们表格里的内容。但同时,我们也发现,当我们LTable组件里涉及到的插槽越来越多的时候,里面的代码也会越来越多。随着我们的项目越来越复杂,需要的插槽可能有几十个甚至上百个,使用插槽的方式进行封装开始显示出了很多问题。我们该如何对这种情况进行优化呢?

动态组件

解决插槽存在的问题

针对上面提出的问题,我从自动化的角度进行了思考,放弃了大量使用插槽,改用组件代替插槽的形式进行优化。将插槽的类型进行汇总,分别定义不同类型的组件去替换插槽,大大减少了由插槽产生的代码。

代码实现

首先在配置文件里面添加了type属性,表示它对应哪个动态组件。还添加了cb回调函数,主要处理对数据的格式进行转化。

export const tableConfig = {
  columnList: [
    {
      type: "text",
      label: "日期",
      prop: "date",
      width: "180"
    },
    {
      type: "image",
      label: "图片",
      prop: "imgSrc",
      width: "180"
    },
    {
      type: "text",
      label: "姓名",
      prop: "name"
    },
    {
      type: "function",
      label: "性别",
      prop: "sex",
      sortable: true,
      cb: data => {
        return data == 1 ? "男" : "女";
      }
    },
    {
      type: "input",
      label: "地址",
      prop: "address"
    },
    {
      type: "slot",
      label: "操作",
      prop: "action",
      slotName: "actions"
    }
  ],
  showIndexColumn: true,
  showSelectColumn: true,
  requestUrl: "api/getData"
};

然后在LTable组件里面做自动化处理,这里需要用到Node里面的require.context方法,他会递归获取相应文件夹下的对应类型文件。

所以我们还需要在相应文件夹下面创建相应的组件,这里我是在components文件夹下创建了control文件夹,control文件夹下放我们对应需要渲染的组件,这里我创建了四个,function、image、input、text,分别对应内容需要转化、图片展示、最基本文字、输入框。根据具体的业务创建不同的组件即可。

control文件夹

我们需要用require.context方法在LTable组件里拿到control文件夹下的所有组件。

const modules = {};
const files = require.context("../control", true, /\index.vue$/);
files.keys().forEach(item => {
  const name = item.split("/")[1];
  modules[`com-${name}`] = files(item).default;
});
console.log(modules, 'modules');

打印modules

注册组件:

components: {
  ...modules
},

我们通过动态组件的方式,根据我们要渲染的表格内容去加载不同的组件:

<el-table-column
  v-for="item in columnList"
  :key="item.prop"
  v-bind="item"
  align="center"
>
  <template slot-scope="scope">
    <slot
      v-if="item.type === 'slot'"
      :name="item.slotName"
      :row="scope.row"
    ></slot>
    <components
      v-else
      :row="scope.row"
      :prop="item.prop"
      :config="item"
      :is="`com-${item.type}`"
    ></components>
  </template>
</el-table-column>

页面里面的内容:

<template>
  <div class="app-container">
    <automation-table v-bind="tableConfig">
      <template #actions="scope">
        <el-button @click="handleClick(scope.row)" type="text" size="small"
          >查看</el-button
        >
        <el-button type="text" size="small">编辑</el-button>
      </template>
    </automation-table>
  </div>
</template>

最后,我们在control文件夹下,给定义的组件写上渲染逻辑:

function组件:

<template>
  <div>
    {{ config.cb && config.cb(row[prop]) }}
  </div>
</template>
<script>
export default {
  props: {
    row: {
      type: Object,
      require: true
    },
    prop: {
      type: String,
      require: true
    },
    config: {
      type: Object,
      require: true
    }
  },
  data() {
    return {};
  }
};
</script>
<style lang="scss" scoped></style>

主要调用配置文件里的cb,传入表格内容作为参数,进行我们想要的内容转化。

image组件:

<template>
  <div>
    <el-image
      style="width: 70px; height: 70px"
      :src="row[prop]"
      :preview-src-list="[row[prop]]"
      fit="cover"
      preview-teleported
    ></el-image>
  </div>
</template>
<script>
export default {
  props: {
    row: {
      type: Object,
      require: true
    },
    prop: {
      type: String,
      require: true
    },
    config: {
      type: Object,
      require: true
    }
  },
  data() {
    return {};
  }
};
</script>
<style lang="scss" scoped></style>

主要将我们传入的文件地址,转化为图片展示出来。

input组件:

<template>
  <div>
    <el-input v-model="row[prop]" clearable></el-input>
  </div>
</template>
<script>
export default {
  props: {
    row: {
      type: Object,
      require: true
    },
    prop: {
      type: String,
      require: true
    },
    config: {
      type: Object,
      require: true
    }
  },
  data() {
    return {};
  }
};
</script>
<style lang="scss" scoped></style>

主要将我们传入的内容绑定到input输入框里面,一般进行编辑操作。

text组件:

<template>
  <div>
    {{ row[prop] }}
  </div>
</template>
<script>
export default {
  props: {
    row: {
      type: Object,
      require: true
    },
    prop: {
      type: String,
      require: true
    },
    config: {
      type: Object,
      require: true
    }
  },
  data() {
    return {};
  }
};
</script>
<style lang="scss" scoped></style>

直接展示表格内容。

最终得到的表格效果:

表格图片

总结

以上就是介绍的两种封装Table组件的方式。核心都是基于配置文件去进行渲染Table,渲染具体的内容可以使用插槽或者动态组件。

如果项目中需要用到的插槽比较多,推荐使用动态组件的方式。

更多关于Vue组件封装Table的资料请关注我们其它相关文章!

(0)

相关推荐

  • vue3 el-table结合seamless-scroll实现表格数据滚动的思路详解

    github开源地址:https://github.com/xfy520/vue3-seamless-scroll 步骤 1. 安装 npm install vue3-seamless-scroll --save 2. vue代码 <template> <el-table :data="tableData" style="width: 100%" class="top" > <el-table-column prop

  • vue开发table数据合并实现详解

    目录 前言 思路梳理 方案一 Element 官方 Table 组件数据合并 注意 方案二 Table-column Scoped Slot 注意 前言 项目中的某个模块,一个勾选表格数据,里面的行数据由于有关联关系,需要多行数据合并,然后勾选时选中一条数据,方便进行下一步业务操作,然后产品经理就指着原型上的表格,说:这里,这里, 数据需要合并...... 功能需求有了,里面有个技术实现点 —— 表格数据合并,下面我们就来分析一下这个表格数据合并的实现 思路梳理 方案一 Element 官方 T

  • vue+elementui实现动态添加行/可编辑的table

    本文实例为大家分享了vue+elementui实现动态添加行.可编辑的table的具体代码,供大家参考,具体内容如下 HTMl代码块: <el-col :span="24">     <el-form-item label="与承租户同户籍成员:" :label-width="formLabelWidth">         <el-table :data="zichandetail.members&quo

  • vue el-table 动态添加行与删除行的实现

    目录 el-table 动态添加行与删除行 el-table 合计行放在首行 首先在el-table ,添加属性 2.定义合计行的位置和样式 3. 合计行的数据 el-table 动态添加行与删除行 项目中有需要动态添加和删除 el-table 行的需要,就学习了下,发现很简单: <template>   <el-dialog     width="50%"     :visible.sync="isShow"     :before-close=

  • Vue中Element的table多选表格如何实现单选

    目录 Element的table多选表格实现单选 vue table单选逻辑 Element的table多选表格实现单选 效果图 1.在多选表格的基础上进行处理, 呈现单选表格的作用 2.主要使用的是ElementUI多选表格中的方法 链接 2.1 select 事件 当用户手动勾选数据行的 Checkbox 时触发的事件 参数selection, row 2.2 row-click 事件 当某一行被点击时会触发该事件 参数 row, column, event 2.3 selection-ch

  • vue表格(table)计算总计方式

    目录 vue表格计算总计 vue table表格合计 ( Element ) vue表格计算总计 <el-table         v-loading="loading"         :summary-method="getSummaries"         show-summary         :data="abcList"         border         tooltip-effect="darkTab

  • Vue业务组件封装Table表格示例详解

    目录 前言 Table组件介绍 Table组件封装思路 了解element Table组件代码 Table组件如何去封装 新建LTable组件 配置文件 配置插槽 动态组件 解决插槽存在的问题 代码实现 总结 前言 这个系列主要是分享自己在工作中常用到的业务组件,以及如何对这些组件进行有效的封装和封装的思路.注:都是基于element ui进行二次封装. 封装组件的基本方法就是通过props和emit进行父子组件的传值和通信.利用插槽.组件等去增加组件的可扩展性和复用性. Table组件介绍 用

  • Vue transx组件切换动画库示例详解

    目录 来个介绍 安装 使用 支持参数 支持事件 支持API 支持的动画类型 说明 来个介绍 先奉上组件库的名称:transx github地址:github.com/tnfe/transx npm参考: www.npmjs.com/package/tra… 示例地址:codesanbox 安装 npm install transx or yarn add transx 使用 <!-- 包裹动画元素 --> <trans-x :time="time" :delay=&q

  • vue封装动态表格方式详解

    目录 前言 实现方式简述 表格实现: func组件 text组件: 调用示例 效果 前言 这里只是提供一种想法并提供一些快速实现,实际这些技巧可以用在很多地方,如:动态表单 实现方式简述 通过json定义要显示的列 通过slot实现自定义列 通过require.context实现组件的自动注册,并通过<components is="xxx"></components>, 调用动态注册的组件 优点: 支持通过slot自定义扩展 支持编写vue文件扩展列的显示方式

  • Hooks封装与使用示例详解

    目录 Hooks是什么? Hooks解决了什么? HOC与HOOK对比 分别使用React与Vue3两种框架封装useThrottle钩子函数 总结 Hooks是什么? 本篇文章主要介绍Hooks如何在React与Vue3两大框架中封装使用. Hooks就是当代码执行在某个执行阶段,触发被钩子钩到的事件函数或者回调函数,Hooks的概念最早在React的V16.8.0版本正式推出,后面Vue3的出现也引入Hooks的概念,两者使用Hooks还是会有所差异. Hooks解决了什么? 完善代码能力

  • Springboot Vue可配置调度任务实现示例详解

    目录 正文 1.表结构: 2.接口: 3.业务层: 4.Mapper 5.前端(Vue): 正文 Springboot + Vue,定时任务调度的全套实现方案. 这里用了quartz这个框架,实现分布式调度任务很不错,关于quarz的使用方式改天补一篇.相当简单. 1.表结构: sys_job 列名 数据类型 长度 是否可空 是否主键 说明 job_id bigint 否 是 任务ID job_name varchar 64 否 是 任务名称 job_group varchar 64 否 是 任

  • vue 自定义组件的写法与用法详解

    三个技能,父组件 -> 子组件传值(props).子组件 -> 父组件传值(emit用来使这个独立的组件通过一些逻辑来融入其他组件中.举个具体点的例子,假如你要做一辆车,车轮是要封装的一个独立组件,props指的就是根据整个车的外形你可以给轮子设置一些你想要的且符合车风格的花纹,图案等:而$emit的作用则是让这些轮子能够和整辆车完美契合的运作起来. (1)使用props可以实现父子组件之间的传值 (2)使用this.$emit()可是实现子组件调用父组件的方法 一.在commponents文

  • Vue.js实现watch属性的示例详解

    目录 1.写在前面 2.watch的实现原理 3.立即执行的watch与回调执行时机 立即执行的回调函数 回调函数的执行时机 4.过期的副作用函数和cleanup 5.写在最后 1.写在前面 在上篇文章中,我们讨论了compted的实现原理,就是利用effect和options参数进行封装.同样的,watch也是基于此进行封装的,当然watch还可以传递第三参数去清理过期的副作用函数.不仅可以利用副作用函数的调度性,去实现回调函数的立即执行,也可以控制回调函数的执行时机. 2.watch的实现原

  • vue electron实现无边框窗口示例详解

    目录 一.前言 二.实现方案 1.创建无边框窗口 2.创建windows窗口控件组件 三.后记 一.前言 无边框窗口是不带外壳(包括窗口边框.工具栏等),只含有网页内容的窗口.对于一个产品来讲,桌面应用带边框的很少,因为丑(我们的UI觉得--与我无关-.-).因此我们就来展开说下,在做无边框窗口时候需要注意的事项以及我踩过的坑. 二.实现方案 1.创建无边框窗口 要创建无边框窗口,只需在 BrowserWindow的 options 中将 frame 设置为 false: const { Bro

  • vue3.2自定义弹窗组件结合函数式调用示例详解

    目录 前言 手写弹窗组件 组件调用 函数式调用 如何使用 含样式完整源码 效果图 前言 涉及的vue3知识点/API,createApp defineProps defineEmits <script setup> v-model <script setup> 就是 setup 语法糖 defineProps 和 props 用法差不多 defineEmits 声明可向其父组件触发的事件 手写弹窗组件 很简单的弹窗组件,支持设置标题 <script setup> def

  • vue整合项目中百度API示例详解

    目录 官网介绍 申请密钥 官方示例 项目实战 创建地图 获取经纬度 创建Map实例 两个坐标点之间的距离 查询地点信息 Vue项目中整合百度API获取地理位置的方法 组件中使用 vue-baidu-map 百度地图官方vue组件 官网介绍 百度地图 JavaScript API 是一套由 JavaScript 语言编写的应用程序接口 可帮助您在网站中,构建功能丰富交互性强的地图应用 支持PC端和移动端,基于浏览器的地图应用开发,且支持HTML5特性的地图开发 官网传送门 百度地图JavaScri

随机推荐