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 操作文件 实现方法小结
Jul 02 Javascript
javascript下利用arguments实现string.format函数
Aug 24 Javascript
javascript的函数、创建对象、封装、属性和方法、继承
Mar 10 Javascript
JavaScript高级程序设计 阅读笔记(十三) js定义类或对象
Aug 14 Javascript
多种方法判断Javascript对象是否存在
Sep 22 Javascript
详解Javascript动态操作CSS
Dec 08 Javascript
分享十五款 jQuery 社交网络分享插件
May 16 Javascript
AngularJS数据源的多种获取方式汇总
Feb 02 Javascript
如何实现json数据可视化详解
Nov 24 Javascript
JS实现随机抽取三人
Nov 06 Javascript
jQuery实现滑动开关效果
Aug 02 jQuery
js实现鼠标点击飘爱心效果
Aug 19 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使用unset()删除数组中某个单元(键)的方法
2015/02/17 PHP
总结PHP如何获取当前主机、域名、网址、路径、端口和参数等
2016/09/09 PHP
记录Yii2框架开发微信公众号遇到的问题及解决方法
2018/07/20 PHP
PHP simplexml_load_string()函数实例讲解
2019/02/03 PHP
PHP利用curl发送HTTP请求的实例代码
2020/07/09 PHP
JavaScript学习笔记(二) js对象
2011/10/25 Javascript
html a标签-超链接中confirm方法使用介绍
2013/01/04 Javascript
用jQuery实现的智能隐藏、滑动效果的返回顶部代码
2014/03/18 Javascript
jQuery实现高亮显示的方法
2015/03/10 Javascript
jQuery实现的淡入淡出二级菜单效果代码
2015/09/15 Javascript
JavaScript仿flash遮罩动画效果
2016/06/15 Javascript
js 基础篇必看(点击事件轮播图的简单实现)
2016/08/20 Javascript
javascript实现获取指定精度的上传文件的大小简单实例
2016/10/25 Javascript
Easyui在treegrid添加控件的实现方法
2017/06/23 Javascript
JS小球抛物线轨迹运动的两种实现方法详解
2017/12/20 Javascript
vue axios请求拦截实例代码
2018/03/29 Javascript
详解Puppeteer 入门教程
2018/05/09 Javascript
jQuery实现的页面详情展开收起功能示例
2018/06/11 jQuery
nodejs异步编程基础之回调函数用法分析
2018/12/26 NodeJs
Vue CLI3基础学习之pages构建多页应用
2019/06/02 Javascript
js面试题之异步问题的深入理解
2020/09/20 Javascript
详解nginx配置vue h5 history去除#号
2020/11/09 Javascript
Vue——解决报错 Computed property &quot;****&quot; was assigned to but it has no setter.
2020/12/19 Vue.js
[01:30]2016国际邀请赛中国区预选赛神秘商店火爆开启
2016/06/26 DOTA
python用pip install时安装失败的一系列问题及解决方法
2020/02/24 Python
python实现Oracle查询分组的方法示例
2020/04/30 Python
Python键鼠操作自动化库PyAutoGUI简介(小结)
2020/05/17 Python
python如何变换环境
2020/07/21 Python
python和C++共享内存传输图像的示例
2020/10/27 Python
Wiggle美国:英国骑行、跑步、游泳、铁人三项商店
2018/10/27 全球购物
主题班会演讲稿
2014/05/22 职场文书
2014年向国旗敬礼活动方案
2014/09/27 职场文书
2014年社区教育工作总结
2014/12/02 职场文书
小学班主任事迹材料
2014/12/17 职场文书
心理健康教育主题班会
2015/08/13 职场文书
会议承办单位欢迎词
2019/07/09 职场文书