Element实现动态表格的示例代码


Posted in Javascript onAugust 02, 2021

【代码背景】

有这样一个业务需求场景,有大概十几张表归属于某个类别,用户希望在同一个页面,通过选择不同的查询指标展示不同的表格,这些表的表头样式类似但是又不完全相同,怎么做呢?

到目前为止所有基于Element UI的表格样式都是直接在页面写死的,像官方这样:

<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>

要解决上述问题,最简单暴力的方式是为每个表写一个单独组件,然后通过select框触发事件切换不同组件路由渲染页面,当然这种方式很笨,也不符合代码复用的基本原则,所以为了偷懒,为了坚守代码复用的基本原则,开始思考有没有更好的方式来解决这个问题。

仔细观察这个<el-table>,表格数据是通过:data绑定的,表格头部数据则是通过<el-table-column>标签展示的,表头数据是不是也可以通过某种传参的方式结合v-for来渲染<el-table-column>的具体数据呢?在度娘的帮助下,果然有大佬已经这样做了,实现了动态表格,参考链接挂在最底下了哦,在此特别感谢免费分享知识的大佬们,知识无价,学无止境。

现将本项目的具体实现代码记录如下,完善了一些代码的注解,尝试帮助理解。

【代码实现】

#1# -> 代码复用的基础是你需要一个可复用的组件

在/components/Table文件夹下新建两个组件

DynamicTable.vue

<template>
  <!-- 动态展示表格 -->
  <el-table :data="tableData" border stripe :height="height" @row-click="handleRowClick">
    <!-- v-for 循环取表头数据 -->
    <template v-for="item in tableHeader">
      <table-column v-if="item.children && item.children.length" :key="item.id" :column-header="item" />
      <el-table-column v-else :key="item.id" :label="item.label" :prop="item.prop" align="center" />
    </template>
  </el-table>
</template>
<script>
  import TableColumn from '@/components/Table/TableColumn'
 
  export default {
    name: 'DynamicTable',
    components: {
      TableColumn
    },
    props: {
      // 表格的数据
      tableData: {
        type: Array,
        required: true
      },
      // 多级表头的数据
      tableHeader: {
        type: Array,
        required: true
      },
      // 表格的高度
      height: {
        type: String,
        default: '300'
      }
    },
    methods: {
      // 行点击事件
      handleRowClick (row, column, event) {
        // console.log(row)
        // console.log(column)
        // console.log(event)
        // 通知调用父组件的row-click事件
        // row作为参数传递过去
        this.$emit('row-click', row)
      }
    }
  }
</script>

TableColumn.vue

<template>
  <el-table-column
    :label="columnHeader.label"
    :prop="columnHeader.label"
    align="center"
  >
    <!--columnHeader对应:column-header-->
    <template v-for="item in columnHeader.children">
      <tableColumn
        v-if="item.children && item.children.length"
        :key="item.id"
        :column-header="item"
      />
      <el-table-column
        v-else
        :key="item.name"
        :label="item.label"
        :prop="item.prop"
        align="center"
      />
    </template>
  </el-table-column>
</template>
 
<script>
  export default {
    name: 'TableColumn',
    props: {
      columnHeader: {
        type: Object,
        required: true
      }
    }
  }
</script>
 
<style scoped>
 
</style>

几点重要说明:

(1)表格头部的传参主要分为两类:带children节点和不带children节点的,如下图所示

Element实现动态表格的示例代码

请注意children节点是为了完成复杂表头的渲染,例如上面这个示例最终的表头渲染样式如下:

Element实现动态表格的示例代码

那么问题来了,<el-table-column>是<el-table>的标签,那这个<table-column>是个啥?

(2)DynamicTable.vue调用TableColumn.vue组件

Element实现动态表格的示例代码

DynamicTable.vue通过:column-header给TableColumn.vue传递带children子节点的表头信息,TableColumn.vue接收到这个节点信息后,主要做了以下两件事情:

第一:通过<el-table-column>渲染了一个label标签

第二:继续判断该节点是否存在children子节点

=> 如果存在children节点,继续通过<table-column>进行渲染,继续把这个子节点传给TableColumn.vue组件,重复上述步骤

=> 如果不存在children节点,表示这是一个终止节点,通过<el-table-column>渲染结束

#2# -> 在展示页面使用动态表格组件

<template>
  <div class="demo">
    <el-card>
      <!--查询区域-->
      <el-row :gutter="10">
        <el-col :span="6">
          <div class="grid-content bg-purple">
            <span style="margin-right: 10px">选择框 -</span>
            <el-select
              v-model="specified_table"
              placeholder="请选择"
            >
              <el-option
                v-for="item in options"
                :key="item.zb_code"
                :label="item.zb_name"
                :value="item.zb_code"
              />
            </el-select>
          </div>
        </el-col>
        <el-col :span="6">
          <div class="grid-content bg-purple">
            <el-button type="primary" plain @click="handleQueryClick">查 询</el-button>
          </div>
        </el-col>
      </el-row>
      <!--表格区域-->
      <dynamic-table
        v-if="dynamicTableShow"
        :table-data="tableData"
        :table-header="tableHeaders"
        :height="'550px'"
      />
    </el-card>
  </div>
</template>
<script>
  // 引入组件
  import DynamicTable from '@/components/Table/DynamicTable'
  // 获取表头信息
  import { getTableHeader02_1, getTableHeader02_2, getTableHeader02_3, getTableHeader02_4 } from '@/api/table-header'
 
  export default {
    name: 'Index',
    components: { // 组件注册
      DynamicTable
    },
    data () {
      return {
        // -- 查询 ----------------------
        options: [
          // { zb_name: '指标名', zb_code: '指标代码' }
        ],
        specified_table: '', // 指标值
        // -- 表格 ----------------------
        dynamicTableShow: true, // DynamicTable组件重新渲染变量
        // 表头数据
        tableHeaders: [],
        // 表格数据
        tableData: []
      }
    },
    created () {
      // api-获取指标的下拉框数据
      getSpecifiedTable().then(res => {
        this.options = res.data
      })
    },
    methods: {
      // 判断值是否在数组中
      isExistArr (arr, val) {
        return arr.includes(val)
      },
      // 重新渲染表格
      refreshTable (zb_code) {
        // 根据value值获取label值
        const obj = this.options.find((item) => {
          return item.zb_code === zb_code
        })
        console.log(zb_code)
        console.log(obj.zb_name)
        // 设置dynamicTableShow为false,使得DynamicTable组件重新渲染
        this.dynamicTableShow = false
        // 根据不同指标渲染不同的表头
        const TBArr01 = ['M01', 'M02', 'M03', 'M05'] // 第1类表
        const TBArr02 = ['M04', 'M07', 'M08', 'M12'] // 第2类表
        const TBArr03 = ['M09', 'M10', 'M11'] // 第3类表
        const TBArr04 = ['M06'] // 第4类表
        if (this.isExistArr(TBArr01, zb_code)) {
          this.tableHeaders = getTableHeader02_1(obj.zb_name) // 渲染表头样式1
        }
        if (this.isExistArr(TBArr02, zb_code)) {
          this.tableHeaders = getTableHeader02_2(obj.zb_name) // 渲染表头样式2
        }
        if (this.isExistArr(TBArr03, zb_code)) {
          this.tableHeaders = getTableHeader02_3(obj.zb_name) // 渲染表头样式3
        }
        if (this.isExistArr(TBArr04, zb_code)) {
          this.tableHeaders = getTableHeader02_4(obj.zb_name) // 渲染表头样式4
        }
        // api - 获取表格数据
        getTableList02(zb_code).then(res => {
          this.tableData = res.data
        })
        // 此处是DOM还没有更新,此处的代码是必须的
        this.$nextTick(() => {
          // DOM现在更新了
          this.dynamicTableShow = true
        })
      },
      // 点击[查询]事件
      handleQueryClick () {
        const zb_code = this.specified_table
        // 校验查询条件不能为空
        if (zb_code === '' || zb_code === undefined) {
          this.$message.warning('指标不能为空!')
        } else {
          console.log('zb_code: ' + zb_code)
          // 重新渲染表头和表格
          this.refreshTable(zb_code)
        }
      }
    }
  }
</script>

使用动态表格组件相对来说比较简单,唯一需要注意的地方是,渲染表格头部跟数据时必须需要添加以下代码,不然页面无法按照预期完成渲染。

this.$nextTick(() => {
    // DOM现在更新了
    this.dynamicTableShow = true
})

关于this.$nextTick()可以参考官网:https://cn.vuejs.org/v2/guide/reactivity.html

Element实现动态表格的示例代码

#3# -> 如何给动态表格根据需求动态添加序号列/索引列

在Element UI官方例子中,如果需要给table添加一个序号列或者索引列非常简单,直接在<el-table>里声明一个特殊的<el-table-column>即可。

<el-table-column type="index" width="50"></el-table-column>

那如何在动态表格组件里添加序号列呢?更甚者如果根据需要自行添加或者不添加?

首先我们来改造 DynamicTable.vue

像官方例子一样,我们先在<el-table>里也声明一个<el-table-column>

<el-table-column v-if="isIndex" type="index" width="100" label="序号" align="center" />

注意到这里有一个v-if绑定了一个isIndex值,这个值就是我们需要在父组件进行传值的关键了

在props里声明isIndex为Boolean类型

props: {
      // 表格的数据
      tableData: {
        type: Array,
        required: true
      },
      // 多级表头的数据
      tableHeader: {
        type: Array,
        required: true
      },
      // 表格的高度
      height: {
        type: String,
        default: '300'
      },
      // 是否需要添加序号列
      isIndex: {
        type: Boolean
      }
}

在展示页面使用组件时通过:is-index传入指定参数

<dynamic-table
        v-if="dynamicTableShow"
        :table-data="tableData"
        :table-header="tableHeaders"
        :height="'550px'"
        :is-index="true"
/>

在同页面表头需要切换的情况下,上面这种写法容易在页面初始化时候单独显示一个序号列,就像下面这样,非常不美观

Element实现动态表格的示例代码

我希望序号列可以和其他普通列一样在表头渲染的时候同时加载,可以这样做

<dynamic-table
        v-if="dynamicTableShow"
        :table-data="tableData"
        :table-header="tableHeaders"
        :height="'550px'"
        :is-index="isAddIndex"
/>

将原本的常量“true”修改成一个变量isAddIndex替代,然后在表头渲染完成的时候将其值修改成true

this.isAddIndex = true

这样序号列就能跟其他普通列同时进行渲染了。

【参考资料】

https://www.jianshu.com/p/9c4ba833658f

https://www.cnblogs.com/llcdxh/p/9473458.html

到此这篇关于Element实现动态表格的示例代码的文章就介绍到这了,更多相关Element 动态表格内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
javascript 流畅动画实现原理
Sep 08 Javascript
基于jquery的textarea发布框限制文字字数输入(添加中文识别)
Feb 16 Javascript
浅谈javascript中的作用域
Apr 07 Javascript
在JavaScript中实现类的方式探讨
Aug 28 Javascript
浅析JavaScript中的typeof运算符
Nov 30 Javascript
javascript中数组的冒泡排序使用示例
Dec 18 Javascript
JavaScript 实现打印,打印预览,打印设置
Dec 30 Javascript
利用JQuery阻止事件冒泡
Dec 01 Javascript
jQuery中select与datalist制作下拉菜单时的区别浅析
Dec 30 Javascript
BootStrap中的Fontawesome 图标
May 25 Javascript
Vue resource中的GET与POST请求的实例代码
Jul 21 Javascript
vue父组件触发事件改变子组件的值的方法实例详解
May 07 Javascript
JavaScript分页组件使用方法详解
webpack的移动端适配方案小结
Jul 25 #Javascript
Vue3.0 手写放大镜效果
ElementUI实现el-form表单重置功能按钮
vue项目多环境配置(.env)的实现
Node与Python 双向通信的实现代码
Jul 16 #Javascript
node.js如何自定义实现一个EventEmitter
Jul 16 #Javascript
You might like
两种php调用Java对象的方法
2006/10/09 PHP
一些需要禁用的PHP危险函数(disable_functions)
2012/02/23 PHP
php匹配字符中链接地址的方法
2014/12/22 PHP
基于thinkPHP实现的微信自定义分享功能示例
2016/09/23 PHP
PHP实现时间日期友好显示实现代码
2019/09/08 PHP
PHP7生产环境队列Beanstalkd用法详解
2020/05/19 PHP
jquery tab标签页的制作
2010/05/10 Javascript
js获取光标位置和设置文本框光标位置示例代码
2014/01/09 Javascript
Js冒泡事件详解及阻止示例
2014/03/21 Javascript
JS+HTML5手机开发之滚动和惯性缓动实现方法分析
2016/06/12 Javascript
jQuery实现两列等高并自适应高度
2016/12/22 Javascript
JS正则表达式之非捕获分组用法实例分析
2016/12/28 Javascript
JavaScript实现审核流程状态的动态显示进度条
2017/03/15 Javascript
浅谈箭头函数写法在ReactJs中的使用
2017/08/22 Javascript
vue 使用eventBus实现同级组件的通讯
2018/03/02 Javascript
Mac下通过brew安装指定版本的nodejs教程
2018/05/17 NodeJs
开发中常用的25个JavaScript单行代码(小结)
2019/06/28 Javascript
Vue实现boradcast和dispatch的示例
2020/11/13 Javascript
[00:12]2018DOTA2亚洲邀请赛SOLO赛 MidOne是否中单第一人?
2018/04/05 DOTA
极简的Python入门指引
2015/04/01 Python
如何将python中的List转化成dictionary
2016/08/15 Python
Python实现微信小程序支付功能
2019/07/25 Python
Python 抓取数据存储到Redis中的操作
2020/07/16 Python
css 如何让背景图片拉伸填充避免重复显示
2013/07/11 HTML / CSS
BOSE德国官网:尽探索之力,享音乐之极
2016/12/11 全球购物
德国最新街头服饰网上商店:BODYCHECK
2019/09/15 全球购物
C++:memset ,memcpy和strcpy的根本区别
2013/04/27 面试题
体育老师的教学自我评价分享
2013/11/19 职场文书
军训自我鉴定怎么写
2014/02/13 职场文书
取保候审保证书
2014/04/30 职场文书
优秀研究生主要事迹
2014/06/03 职场文书
节能环保标语
2014/06/12 职场文书
2015大学生求职信范文
2015/03/20 职场文书
2015年学校财务工作总结
2015/05/19 职场文书
2015年英语教学工作总结
2015/05/25 职场文书
2015年工商局个人工作总结
2015/07/23 职场文书