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去掉字符串里的所有空格
Feb 08 Javascript
用JavaScript 处理 URL 的两个函数代码
Aug 13 Javascript
JS保存、读取、换行、转Json报错处理方法
Jun 14 Javascript
javascript计算当月剩余天数(天数计算器)示例代码
Jan 09 Javascript
javascript实现密码验证
Nov 10 Javascript
Bootstrap每天必学之标签与徽章
Nov 27 Javascript
D3.js实现雷达图的方法详解
Sep 22 Javascript
js从输入框读取内容,比较两个数字的大小方法
Mar 13 Javascript
Cookies 和 Session的详解及区别
Apr 21 Javascript
JS生成随机打乱数组的方法示例
Dec 23 Javascript
详解如何配置vue-cli3.0的vue.config.js
Aug 23 Javascript
Vue-router 报错NavigationDuplicated的解决方法
Mar 31 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中大括号作用介绍
2012/03/22 PHP
php如何调用webservice应用介绍
2012/11/24 PHP
php 读取文件头判断文件类型的实现代码
2013/08/05 PHP
php获取访问者IP地址汇总
2015/04/24 PHP
PHP的mysqli_set_charset()函数讲解
2019/01/23 PHP
form.submit()不能提交表单的原因分析
2014/10/23 Javascript
jQuery新窗口打开外链接
2016/07/21 Javascript
jQuery Ajax 异步加载显示等待效果代码分享
2016/08/01 Javascript
微信小程序 Video API实例详解
2016/10/02 Javascript
基于vue的下拉刷新指令和滚动刷新指令
2016/12/23 Javascript
基于JavaScript实现瀑布流效果
2017/03/29 Javascript
浅谈在fetch方法中添加header后遇到的预检请求问题
2017/08/31 Javascript
Nodejs进阶之服务端字符编解码和乱码处理
2017/09/04 NodeJs
JavaScript实现异步图像上传功能
2018/07/12 Javascript
nodejs(officegen)+vue(axios)在客户端导出word文档的方法
2018/07/31 NodeJs
解决微信小程序中的滚动穿透问题
2019/09/16 Javascript
JavaScript中Object、map、weakmap的区别分析
2020/12/15 Javascript
[01:48]2018DOTA2亚洲邀请赛主赛事第二日五佳镜头 VG完美团战逆转TNC
2018/04/05 DOTA
Python连接PostgreSQL数据库的方法
2016/11/28 Python
Python爬虫番外篇之Cookie和Session详解
2017/12/27 Python
python基础教程项目四之新闻聚合
2018/04/02 Python
django 解决自定义序列化返回处理数据为null的问题
2020/05/20 Python
HTML5全屏(Fullscreen)API详细介绍
2015/04/24 HTML / CSS
美国农场鲜花速递:The Bouqs
2018/07/13 全球购物
英国第一摩托车和摩托车越野配件商店:GhostBikes
2019/03/10 全球购物
关于毕业的广播稿
2014/01/10 职场文书
中药专业毕业自荐书范文
2014/02/08 职场文书
《鹬蚌相争》教学反思
2014/04/22 职场文书
学习党的群众路线教育实践活动心得体会范文
2014/11/03 职场文书
2015年七一建党节活动总结
2015/03/20 职场文书
交通事故责任认定书
2015/08/06 职场文书
2016党风廉政建设心得体会范文
2016/01/25 职场文书
经典格言警句:没有热忱,世间便无进步
2019/11/13 职场文书
MySQL 全文检索的使用示例
2021/06/07 MySQL
详解Oracle块修改跟踪功能
2021/11/07 Oracle
Nginx如何配置根据路径转发详解
2022/07/23 Servers