在 Vue3 + Element Plus 中生成动态表格,动态修改表格,多级表头,合并单元格

您所在的位置:网站首页 vue前端渲染表格,有合并单元格 在 Vue3 + Element Plus 中生成动态表格,动态修改表格,多级表头,合并单元格

在 Vue3 + Element Plus 中生成动态表格,动态修改表格,多级表头,合并单元格

2024-07-11 17:06| 来源: 网络整理| 查看: 265

在 Vue3 + Element Plus 中生成动态表格,动态修改表格,多级表头,合并单元格

本文完整版:《在 Vue3 + Element Plus 中生成动态表格,动态修改表格,多级表头,合并单元格》

在 Vue 中,表格组件是使用频率及复杂度排名第一的组件,前端经常需要根据后台返回的数据动态渲染表格,比如动态表格如何生成,因为表格的列并不是固定的,在未知表格具体有哪些列的场景下,前端如何动态渲染表格数据。又或者需要把表格单元格进行合并处理,比如第一列是日期,需要把相同的日期进行合并,这样表格看起来会更加清晰。 本文手把手教你如何在 Vue3 + Element Plus 中创建表格、生成动态表格、创建动态多级表头、表格行合并、列合并等问题。

如果你正在搭建后台管理工具,又不想处理前端问题,推荐使用卡拉云 ,卡拉云是新一代低代码开发工具,可一键接入常见数据库及 API ,无需懂前端,仅需拖拽即可快速搭建属于你自己的后台管理工具,一周工作量缩减至一天,详见本文文末。

通过本文你可以学到

如何在 Element Plus 中生成动态表格 如何在 Element Plus 中动态修改表格 如何在 Element Plus 中创建动态多级表头

先来展示个「动态修改表格」的最终效果图吧 Vue3 + Element Plus动态修改表格

Vue3 + Element Plus 配置环境

先使用 vue-cli 初始化应用,这里我们选择 vue3 的版本:

vue create kalacloud-vue3-element-plus-table // OR npx vue create kalacloud-vue3-element-plus-table

然后安装 UI 框架 Element Plus:

npm install element-plus --save // OR yarn add element-plus

安装完成后,在项目里导入 ElementPlus,修改 main.js 如下:

import { createApp } from 'vue' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' import App from './App.vue' const app = createApp(App) app.use(ElementPlus) app.mount('#app')

导入后,就可以启动项目了,执行以下命令:

看到以下界面说明项目成功启动了!后面就可以进入本教程的正式内容了。

kalacloud-卡拉云-初始化项目

Vue3 + Element Plus 生成动态表格

有一个场景是表格列并不是固定的,不能在前端写死,而是需要通过后端返回的数据进行动态渲染,比如后端返回了如下的表头数据:

tableHeader: { name: "姓名", birth: "生日", address: "地址", age: "年龄", phone: "电话", }

这个对象中的 key 对应表格数据中的 prop,value 对应实际显示的 label,这样通过一个简单的对象,就可以连接表头和 表格body 之间的关系。然后还需要后端返回具体的表格数据:

tableData: [{ name: '张三', date: '2016-05-02', address: '上海市普陀区金沙江路 1518 弄', age: 18, phone:"12345678910", }, { date: '2016-05-04', name: '李四', address: '上海市普陀区金沙江路 1517 弄', age: 19, phone:"12345678911", }, { date: '2016-05-01', name: '王五', address: '上海市普陀区金沙江路 1519 弄', age: 20, phone:"12345678912", }, { date: '2016-05-03', name: '赵六', address: '上海市普陀区金沙江路 1516 弄', age: 21, phone:"12345678913", }]

实现表格列动态渲染的功能,需要用到一个很关键的 vue 指令,那就是 v-for,v-for 不仅可以遍历数据,也可以遍历对象:

{{ key }}: {{ value }}

这里我们就需要用到这个特性,来对 tableHeader 进行遍历,获取 key 和 value。基于以上讲解,现在我们具体实践一下如何实现表格列的动态渲染。在 components 目录中新建 DynamicTable.vue:

Vue3 + Element plus 动态表格 export default { name: "test", data() { return { tableHeader: { name: "姓名", birth: "生日", address: "地址", age: "年龄", phone: "电话", }, tableData: [{ name: '张三', address: '上海市普陀区金沙江路 1518 弄', birth: '2016-05-02', age: 18, phone: "12345678910", }, { name: '李四', birth: '2016-05-04', address: '上海市普陀区金沙江路 1517 弄', age: 19, phone: "12345678911", }, { name: '王五', birth: '2016-05-01', address: '上海市普陀区金沙江路 1519 弄', age: 20, phone: "12345678912", }, { name: '赵六', birth: '2016-05-03', address: '上海市普陀区金沙江路 1516 弄', age: 21, phone: "12345678913", }] } }, }

组件编写完成后,修改 App.vue,导入该组件即可:

import DynamicTable from './components/DynamicTable.vue' export default { name: 'App', components: { DynamicTable } } #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; }

保存后页面会自动热更新,实现效果如下:

kalacloud-卡拉云-动态表格

这个只是比较基本的使用,如果某些列有一些定制需求,比如需要支持根据日期排序,这个时候可以对 tableHeader 进行改造,使 value 是一个对象,这样就可以携带更多的表头配置信息:

tableHeader: { name: { label: "姓名", sort: true, }, birth: { label: "生日", sort: false, }, address: { label: "地址", sort: false, }, age: { label: "年龄", sort: true, }, phone: { label: "电话", sort: false, } },

然后再改造 el-table 如下:

kalacloud-卡拉云-动态列排序

以上就实现了基于动态列的表头配置,这里的关键在于 tableHeader 的数据结构如何定义,可以把列信息都放在 tableHeader 中,然后再通过 v-for 循环列就可以渲染出对应的表格列。当然 tableHeader 也可以是一个数组,使用方法都是类似的,大家可以自己去尝试一下。

扩展阅读:《多款好用的 vue 表单设计器推荐测评》

Vue3 + Element Plus 动态修改表格

基于以上的思路,我们还可以做的更多,比如动态添加指定行,指定列,或者删除指定行或者列等操作,都是使用相同的思路来实现。我们来具体实践一下,这里我们需要用到 @element-plus/icons-vue,先安装一下:

# NPM npm install @element-plus/icons-vue # Yarn yarn add @element-plus/icons-vue

然后在 main.js 中导入:

import * as ElementPlusIconsVue from '@element-plus/icons-vue' const app = createApp(App) for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) }

在 components 目录下新建 DynamicModifyTable.vue:

Vue3 + Element plus 动态修改表格 「卡拉云 - 极速搭建企业内部工具,十倍提升开发效率」 {{ scope.row[item.prop] }} 上方插入一行 下方插入一行 删除当前列 前方插入一列 后方插入一列 编辑 确定 删除 const item = { name: '', birth: '', province: "", city: "", address: '', phone: "", } const header = { prop: "key", label: "自定义", editable: false, type: "input", } export default { name: "DynamicModifyTable", data() { return { tableHeader: [ { prop: "name", label: "姓名", editable: false, type: "input", }, { prop: "birth", label: "生日", editable: false, type: "date" }, { prop: "phone", label: "电话", editable: false, type: "input" }, { prop: "province", label: "省份", editable: false, type: "input" }, { prop: "city", label: "市区", editable: false, type: "input" }, { prop: "address", label: "详细地址", editable: false, type: "input" } ], tableData: [{ name: '张三', province: "上海市", city: "普陀区", address: "金沙江路 1518 弄", birth: '2016-05-02', phone: "12345678910", }, { name: '李四', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1517 弄', age: 19, phone: "12345678911", }, { name: '王五', birth: '2016-05-01', province: "上海市", city: "普陀区", address: '金沙江路 1519 弄', phone: "12345678912", }, { name: '赵六', birth: '2016-05-03', province: "上海市", city: "普陀区", address: '金沙江路 1516 弄', phone: "12345678913", }] } }, methods: { handleEdit(row) { row.editable = true; }, handleDelete(index) { this.tableData.splice(index, 1); }, prepend(index) { item.editable = true this.tableData.splice(index, 0, item); }, append(index) { item.editable = true this.tableData.splice(index + 1, 0, item); }, deleteCurrentColumn(index) { this.tableHeader.splice(index, 1); }, insertBefore(index) { header.editable = true; this.tableHeader.splice(index, 0, header); Vue3 + Element Plus 创建动态多级表头

多级表头的实现比较简单,主要是通过 el-table-column 的嵌套来完成的,在 components 目录下新建 MultiHeaderTable.vue 文件:

Vue3 + Element plus 动态表格 export default { name: "MultiHeaderTable", data() { return { tableHeader: [ { prop: "name", label: "姓名", }, { prop: "birth", label: "生日", }, { prop: "phone", label: "电话", }, { label: "地址", children: [ { prop: "province", label: "省份", }, { prop: "city", label: "市区", }, { prop: "address", label: "详细地址", } ] } ], tableData: [{ name: '张三', province: "上海市", city: "普陀区", address: "金沙江路 1518 弄", birth: '2016-05-02', phone: "12345678910", }, { name: '李四', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1517 弄', age: 19, phone: "12345678911", }, { name: '王五', birth: '2016-05-01', province: "上海市", city: "普陀区", address: '金沙江路 1519 弄', phone: "12345678912", }, { name: '赵六', birth: '2016-05-03', province: "上海市", city: "普陀区", address: '金沙江路 1516 弄', phone: "12345678913", }] } }, } 对于 `tableHeader` 的定义,我们通过 `children` 字段来指定当前列的二级表头,但是会发现效果并不是我们预期的那样: ![kalacloud-卡拉云-错误演示动态多级表头](./images/04-kalacloud-vue3-element-plug-error.png "04-kalacloud-vue3-element-plug-error.png") 这是为什么呢?原来是因为 `el-table-column` 会检测内部是否还有 `el-table-column`,如果有的话,默认会显示内层的 `el-table-column`,但是在一级表头的情况下,内层 `el-table-column` 并没有值。所以我们需要简单修改一下代码,那就是通过 `v-if="item.children"` 来判断当前列是否有二级表头:

{ if (columnIndex === 0) {

if (rowIndex % 2 === 0) { return { rowspan: 2, //合并的行数 colspan: 1, //合并的列数 } } else { return { rowspan: 0, colspan: 0, } }

}}

但是在动态数据的场景下,这种方法就不适用了,因为前端的表格数据往往是后端通过接口返回的。比如我们有以下数据结构:

tableData: [{ name: '张三', province: "上海市", city: "普陀区", address: "金沙江路 1518 弄", birth: '2016-05-02', phone: "12345678910",}, { name: '李四', birth: '2016-05-02', province: "上海市", city: "普陀区", address: '金沙江路 1517 弄', age: 19, phone: "12345678911",}, { name: '王五', birth: '2016-05-03', province: "上海市", city: "普陀区", address: '金沙江路 1519 弄', phone: "12345678912",}, { name: '赵六', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1516 弄', phone: "12345678913",}, { name: '孙七', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1516 弄', phone: "12345678913",}, { name: '周八', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1516 弄', phone: "12345678913",}, { name: '吴九', birth: '2016-05-06', province: "上海市", city: "普陀区", address: '金沙江路 1516 弄', phone: "12345678913",}]

我们的需求是把相同 `birth` 进行合并。在 `components` 目录下新建 `RowMergeTable.vue` 文件:

Vue3 + Element plus 动态行合并表格

this.spanArr = []; return { tableHeader: [ { prop: "birth", label: "生日", }, { prop: "name", label: "姓名", }, { prop: "phone", label: "电话", }, { prop: "province", label: "省份", }, { prop: "city", label: "市区", }, { prop: "address", label: "详细地址", } ], tableData: [{ name: '张三', province: "上海市", city: "普陀区", address: "金沙江路 1518 弄", birth: '2016-05-02', phone: "12345678910", }, { name: '李四', birth: '2016-05-02', province: "上海市", city: "普陀区", address: '金沙江路 1517 弄', age: 19, phone: "12345678911", }, { name: '王五', birth: '2016-05-03', province: "上海市", city: "普陀区", address: '金沙江路 1519 弄', phone: "12345678912", }, { name: '赵六', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1520 弄', phone: "12345678913", }, { name: '孙七', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1521 弄', phone: "12345678913", }, { name: '周八', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1522 弄', phone: "12345678913", }, { name: '吴九', birth: '2016-05-06', province: "上海市", city: "普陀区", address: '金沙江路 1523 弄', phone: "12345678913", }] }

}, created() {

this.getSpanArr(this.tableData);

}, methods: {

getSpanArr(data) { for (var i = 0; i < data.length; i++) { if (i === 0) { this.spanArr.push(1); this.pos = 0 } else { if (data[i].birth === data[i - 1].birth) { this.spanArr[this.pos] += 1; this.spanArr.push(0); } else { this.spanArr.push(1); this.pos = i; } } } }, objectSpanMethod({ rowIndex, columnIndex }) { if (columnIndex === 0) { const _row = this.spanArr[rowIndex]; const _col = _row > 0 ? 1 : 0; return { rowspan: _row, colspan: _col } } }

}}

上面的例子就实现了行合并的功能: ![kalacloud-卡拉云-动态行合并](https://kalacloud.com/static/8efdf694fe520cf8ef6d2ed466ac32fb/60708/05-kalacloud-vue3-element-plus-rowmerge.png) 因为表格的数据是动态的,所以我们需要事先通过计算,来得知哪些行是需要合并的,这里就是通过 `getSpanArr` 方法来实现的,全局维护了一个 `spanArr` 变量,用于记录每一行需要合并的数字,`pos` 是 `spanArr` 的索引,这样就可以根据索引来动态设置需要合并的行树。当 `i === 0`,说明是第一行数据,向 `spanArr` 数组中 `push` 1,当 `i !== 0`,此时就需要比较当前行与前一行数据的 `birth` 是否相等,如果相等,则利用索引,修改当前行需要合并的行数。 `objectSpanMethod` 方法,在 `el-table` 渲染每一行数据的时候都会执行,这样就可以通过 `rowIndex` 来获取每一行需要合并的行数信息,来实现行合并的功能。 那么如何实现多行合并?其实也是一样的思路,通过 `spanMap` 可以存储多个列的行合并信息。在 `components` 下新建 `MultiRowMergeTable.vue`:

Vue3 + Element plus 动态多行合并表格

this.spanMap = {}; this.mergedColumns = ["birth", "province", "city"] return { tableHeader: [ { prop: "birth", label: "生日", }, { prop: "name", label: "姓名", }, { prop: "phone", label: "电话", }, { prop: "province", label: "省份", }, { prop: "city", label: "市区", }, { prop: "address", label: "详细地址", } ], tableData: [{ name: '张三', province: "上海市", city: "普陀区", address: "金沙江路 1518 弄", birth: '2016-05-02', phone: "12345678910", }, { name: '李四', birth: '2016-05-02', province: "上海市", city: "普陀区", address: '金沙江路 1517 弄', age: 19, phone: "12345678911", }, { name: '王五', birth: '2016-05-03', province: "上海市", city: "普陀区", address: '金沙江路 1519 弄', phone: "12345678912", }, { name: '赵六', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1520 弄', phone: "12345678913", }, { name: '孙七', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1521 弄', phone: "12345678913", }, { name: '周八', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1522 弄', phone: "12345678913", }, { name: '吴九', birth: '2016-05-06', province: "上海市", city: "普陀区", address: '金沙江路 1523 弄', phone: "12345678913", }] }

}, created() {

this.getSpanArr(this.tableData);

}, methods: {

getSpanArr(data) { for (var i = 0; i < data.length; i++) { if (i === 0) { this.mergedColumns.forEach(column => { this.spanMap[column] = { spanArr: [1], pos: 0 } }) } else { this.mergedColumns.forEach(column => { if (data[i][column] === data[i - 1][column]) { this.spanMap[column].spanArr[this.spanMap[column].pos] += 1; this.spanMap[column].spanArr.push(0) } else { this.spanMap[column].spanArr.push(1); this.spanMap[column].pos = i; } }) } } }, objectSpanMethod({ column, rowIndex }) { if (this.spanMap[column.property]) { const _row = this.spanMap[column.property].spanArr[rowIndex]; const _col = _row > 0 ? 1 : 0; return { rowspan: _row, colspan: _col } } }

}}

实现效果如下: ![kalacloud-卡拉云-动态多行合并](https://kalacloud.com/static/b02bf3557a64475277e78b69657beee1/b8765/06-kalacloud-vue3-element-plus-mutil-row.png) 动态多行合并的需求往往更常见,需要把每一列中,相同的数据进行合并,都可以参照这个思路来实现。 扩展阅读:《[Vue + Node.js 全栈开发实战教程 - 手把手教你搭建「文件上传」管理后台](https://kalacloud.com/blog/vue-axios-multiple-node-express-file-upload/)》 ## Vue3 + Element Plus 表格中单元格列合并 接下来,我们来看下如何实现列的合并,其实思路是和行合并类似的,也需要用到 `span-method` 这个方法,唯一不同的在于,列合并需要处理被合并列的原始数据,否则被合并列的原始数据会填充到合并之后的表格里,这样说可能有点抽象,我们写来写一个例子,在 components 下新建 ColumnMergeTable.vue:

Vue3 + Element plus 动态表格列合并

return { tableHeader: [ { prop: "birth", label: "生日", }, { prop: "name", label: "姓名", }, { prop: "phone", label: "电话", }, { prop: "province", label: "省份", }, { prop: "city", label: "市区", }, { prop: "address", label: "详细地址", } ], tableData: [{ name: '张三', province: "上海市", city: "普陀区", address: "金沙江路 1518 弄", birth: '2016-05-02', phone: "12345678910", }, { name: '李四', birth: '2016-05-02', province: "上海市", city: "普陀区", address: '金沙江路 1517 弄', age: 19, phone: "12345678911", }, { name: '王五', birth: '2016-05-03', province: "上海市", city: "普陀区", address: '金沙江路 1519 弄', phone: "12345678912", }, { name: '赵六', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1520 弄', phone: "12345678913", }, { name: '孙七', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1521 弄', phone: "12345678913", }, { name: '周八', birth: '2016-05-04', province: "上海市", city: "普陀区", address: '金沙江路 1522 弄', phone: "12345678913", }, { name: '吴九', birth: '2016-05-06', province: "上海市", city: "普陀区", address: '金沙江路 1523 弄', phone: "12345678913", }] }

}, methods: {

objectSpanMethod({ rowIndex, columnIndex }) { // 隐藏第二行或者第三行的列 if (rowIndex === 1 || rowIndex === 2) { // 合并第二行 if (columnIndex === 1) { // 从第二列开始 return [1, 3] //或者返回如下形式也可以 // return { // rowspan: 1, // colspan: 3 // } // 这里的 else if 即使用来处理被合并列的原始数据的情况,需要隐藏原始单元格 } else if (columnIndex === 2 || columnIndex === 3) { return [0, 0] } } }

}}

可以看出来,列合并其实比行合并简单一些,返回一个数组更容易理解一些,数组的第一项表示合并的起始列,第二项表示合并的终止列,其区间的所有列都会合并成一列,被合并的列还需要通过 \[0, 0\] 来隐藏对应的单元格,这个是和行合并不同的地方。 **扩展阅读:**《[Vue echarts 使用教程](https://kalacloud.com/blog/vue-echarts-tutorial/)》 ## Vue3 + Element Plus 动态表格源代码 本教程所写源代码可在我们的 [github](https://github.com/kalacloudCode/how-to-build-dynamic-table-in-vue-element-plus) 上找到。 ## 动态表格与卡拉云 本文详细讲解如何 Vue3 + Element Plus 中如何创建动态表格的问题。其实如果你根本不想处理复杂的前端问题,完全可以使用卡拉云来处理前端表格,卡拉云内置表格组件,直接鼠标拖拽即可生成,不仅可以处理动态表格,内容实时编辑以及表格中展示图片等功能,还有强大的过滤筛选、数据导出功能。 ![卡拉云内置表格](https://kalacloud.com/static/b9481a4b63d08768c2658fa50e81cd84/42be1/07-kalacloud.jpg) 卡拉云可帮你快速搭建企业内部工具,下图为使用卡拉云搭建的内部广告投放监测系统,无需懂前端,仅需拖拽组件,10 分钟搞定。你也可以快速搭建一套属于你的后台管理工具。 ![卡拉云企业内部工具](https://kalacloud.com/static/b9481a4b63d08768c2658fa50e81cd84/8369b/09-kalacloud.webp) [卡拉云](https://kalacloud.com/)是新一代低代码开发平台,与前端框架 Vue、React等相比,卡拉云的优势在于不用首先搭建开发环境,直接注册即可开始使用。开发者完全不用处理任何前端问题,只需简单拖拽,即可快速生成所需组件,可一键接入常见数据库及 API,根据引导简单几步打通前后端,数周的开发时间,缩短至 1 小时。立即免费[试用卡拉云](https://my.kalacloud.com/signup)。 **扩展阅读:** - [Vue form 表单异步验证终极教程](https://kalacloud.com/blog/vue-form-validate-tutorial/) - [最好用的 6 款 MongoDB GUI 管理工具横向测评](https://kalacloud.com/blog/best-mongodb-gui-tools/) - [5 款最棒的 Vue UI 移动端组件库 - 特别针对国内使用场景推荐](https://kalacloud.com/blog/best-vue-mobile-ui-component-libraries/) - [顶级好用的 5 款 Vue table 表格组件测评与推荐](https://kalacloud.com/blog/best-vue-data-table-grid/)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3