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 相关文章推荐
document.all还是document.getElementsByName?
Jul 21 Javascript
23个Javascript弹出窗口特效整理
Feb 25 Javascript
jquery ajax传递中文参数乱码问题及解决方法说明
Feb 07 Javascript
js实现上传图片预览的方法
Feb 09 Javascript
JavaScript日期类型的一些用法介绍
Mar 02 Javascript
谈谈JavaScript类型系统之Math
Jan 06 Javascript
js编写当天简单日历效果【实现代码】
May 03 Javascript
两行代码轻松搞定JavaScript日期验证
Aug 03 Javascript
seajs模块之间依赖的加载以及模块的执行
Oct 21 Javascript
form表单数据封装成json格式并提交给服务器的实现方法
Dec 14 Javascript
为vue-router懒加载时下载js的过程中添加loading提示避免无响应问题
Apr 03 Javascript
vue-cli开发环境实现跨域请求的方法
Apr 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
Dedecms常用函数解析
2008/02/01 PHP
用php实现百度网盘图片直链的代码分享
2012/11/01 PHP
10条php编程小技巧
2015/07/07 PHP
Convert Seconds To Hours
2007/06/16 Javascript
jquery $.ajax入门应用一
2008/11/19 Javascript
JSON 和 JavaScript eval使用说明
2010/06/13 Javascript
Jquery拖拽并简单保存的实现代码
2010/11/28 Javascript
探讨js中的双感叹号判断
2013/11/11 Javascript
jquery实现的代替传统checkbox样式插件
2015/06/19 Javascript
JavaScript程序开发之JS代码放置的位置
2016/01/15 Javascript
JavaScript常用函数工具集:lao-utils
2016/03/01 Javascript
js css实现垂直方向自适应的三角提示菜单
2016/06/26 Javascript
Javascript实现数组中的元素上下移动
2017/04/28 Javascript
分析JS单线程异步io回调的特性
2017/12/01 Javascript
基于 Immutable.js 实现撤销重做功能的实例代码
2018/03/01 Javascript
vue-test-utils初使用详解
2019/05/23 Javascript
详解JavaScript执行模型
2020/11/16 Javascript
[06:53]DOTA2每周TOP10 精彩击杀集锦vol.3
2014/06/25 DOTA
Python使用htpasswd实现基本认证授权的例子
2014/06/10 Python
利用Python将每日一句定时推送至微信的实现方法
2018/08/13 Python
Python对excel文档的操作方法详解
2018/12/10 Python
Python后台管理员管理前台会员信息的讲解
2019/01/28 Python
Python实现的银行系统模拟程序完整案例
2019/04/12 Python
python跳出双层for循环的解决方法
2019/06/24 Python
python搜索算法原理及实例讲解
2020/11/18 Python
css图标制作教程制作云图标
2014/01/19 HTML / CSS
html5 div布局与table布局详解
2016/11/16 HTML / CSS
编程实现去掉XML的重复结点
2014/05/28 面试题
焊接专业毕业生求职信
2013/10/01 职场文书
新闻专业推荐信范文
2013/11/20 职场文书
政府采购方案
2014/06/12 职场文书
社区党员志愿服务活动方案
2014/08/18 职场文书
小学生感恩老师演讲稿
2014/08/28 职场文书
大学团日活动总结书
2015/05/11 职场文书
起诉状范本
2015/05/20 职场文书
2016年幼儿园教研活动总结
2016/04/05 职场文书