vue+element实现动态表格:根据后台返回的属性名和字段动态生成可变表格

本文介绍了如何在Vue应用中结合ElementUI构建一个动态表格,根据后台返回的属性名和字段实时调整展示,特别关注了如何处理scope.row中的动态字段名问题,适合前端开发者参考。
Vue3 + Element Plus(Element-UIVue3 版本)中实现**动态多级表头表格的导出功能**,需要结合 `el-table` 的多级表头能力与前端 Excel 导出库(如 [SheetJS / xlsx](https://github.com/SheetJS/sheetjs))来完成。由于 Element Plus 表格支持嵌套 `el-table-column` 实现多级表头,但原生不支持导出,因此需手动解析表头结构并生成对应的 Excel 文件。 下面是一个完整的解决方案: --- ### ✅ 功能目标: 1. 支持 **动态配置的多级表头**(任意层级) 2. 使用 `Element Plus` 的 `<el-table>` 展示数据 3. 点击按钮将表格(含多级表头)导出为 `.xlsx` 文件 --- ### ✅ 所需依赖 ```bash npm install xlsx ``` --- ### ✅ 示例代码(Vue3 + Composition API + Element Plus) ```vue <template> <div> <el-button @click="exportToExcel">导出为 Excel</el-button> <el-table :data="tableData" border style="width: 100%; margin-top: 20px" ref="tableRef" > <!-- 动态渲染多级表头 --> <template v-for="col in tableColumns" :key="col.prop"> <el-table-column v-if="!col.children" :prop="col.prop" :label="col.label" :width="col.width" /> <el-table-column v-else :label="col.label" :width="col.width" > <template v-for="child in col.children" :key="child.prop"> <el-table-column :prop="child.prop" :label="child.label" :width="child.width" /> </template> </el-table-column> </template> </el-table> </div> </template> <script setup> import { ref, reactive } from 'vue' import * as XLSX from 'xlsx' // 模拟数据 const tableData = ref([ { name: '张三', info_age: 25, info_city: '北京', score_chinese: 88, score_math: 92 }, { name: '李四', info_age: 27, info_city: '上海', score_chinese: 76, score_math: 98 }, { name: '王五', info_age: 24, info_city: '深圳', score_chinese: 90, score_math: 85 } ]) // 多级表头定义(动态可变) const tableColumns = reactive([ { prop: 'name', label: '姓名', width: 100 }, { label: '个人信息', children: [ { prop: 'info_age', label: '年龄', width: 80 }, { prop: 'info_city', label: '城市', width: 100 } ] }, { label: '成绩信息', children: [ { prop: 'score_chinese', label: '语文', width: 80 }, { prop: 'score_math', label: '数学', width: 80 } ] } ]) // 将多级表头扁平化,并记录每列的完整路径用于映射数据 function flattenHeaders(columns, parentPath = '', parentLabel = '') { let result = [] columns.forEach(col => { if (col.children && col.children.length > 0) { const groupLabel = parentLabel ? `${parentLabel} - ${col.label}` : col.label col.children.forEach(child => { result.push({ prop: child.prop, header: [groupLabel, child.label], // 用于生成两层表头 valuePath: `${parentPath}${child.prop}` }) }) } else { result.push({ prop: col.prop, header: [col.label], valuePath: col.prop }) } }) return result } // 导出为 Excel const exportToExcel = () => { const flatHeaders = flattenHeaders(tableColumns) // 构建表头行(二维数组,支持多级) const headerRows = [[], []] // 第一行:主分组;第二行:具体字段名 const data = [] flatHeaders.forEach(item => { // 填充第一行(分组名) if (item.header.length === 2) { headerRows[0].push(item.header[0]) headerRows[1].push(item.header[1]) } else { headerRows[0].push(item.header[0]) headerRows[1].push('') // 第二行为空 } }) // 合并单元格逻辑(仅对第一行分组合并) const merges = [] let lastGroup = null let groupStartCol = 0 headerRows[0].forEach((groupLabel, index) => { if (groupLabel !== lastGroup) { if (lastGroup !== null) { if (index - groupStartCol > 1) { merges.push({ s: { r: 0, c: groupStartCol }, // start e: { r: 0, c: index - 1 } // end }) } } lastGroup = groupLabel groupStartCol = index } }) // 添加最后一个组的合并 if (headerRows[0].length - groupStartCol > 1 && lastGroup) { merges.push({ s: { r: 0, c: groupStartCol }, e: { r: 0, c: headerRows[0].length - 1 } }) } // 填充数据行 tableData.value.forEach(row => { const rowData = [] flatHeaders.forEach(item => { rowData.push(row[item.prop] || '') }) data.push(rowData) }) // 使用 SheetJS 创建工作簿工作表 const worksheet = XLSX.utils.aoa_to_sheet([]) // 写入第一行(分组) XLSX.utils.sheet_add_aoa(worksheet, [headerRows[0]], { origin: 'A1' }) // 写入第二行(字段) XLSX.utils.sheet_add_aoa(worksheet, [headerRows[1]], { origin: 'A2' }) // 写入数据行(从第3行开始) XLSX.utils.sheet_add_aoa(worksheet, data, { origin: 'A3' }) // 设置列宽(可选) const colWidths = flatHeaders.map(item => ({ wch: 12 })) worksheet['!cols'] = colWidths // 设置合并单元格 worksheet['!merges'] = merges // 创建工作簿并导出 const workbook = XLSX.utils.book_new() XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1') // 触发下载 XLSX.writeFile(workbook, '动态多级表头导出.xlsx') } </script> <style scoped> .el-table { margin-top: 20px; } </style> ``` --- ### 🔍 代码解释 | 部分 | 说明 | |------|------| | `tableColumns` | 定义了支持嵌套 `children` 的多级结构,是动态可配置的核心 | | `flattenHeaders()` | 将嵌套列结构展平,提取每个叶子节点的路径、标签数据属性 | | `headerRows` | 构造两行表头:第一行为“个人信息”、“成绩信息”等大类,第二行为具体字段 | | `merges` | 记录需要合并的单元格范围(第一行中相同分组的连续列) | | `XLSX.utils.aoa_to_sheet` | 使用数组 of 数组方式构建表格 | | `sheet_add_aoa` | 分别写入不同行的数据 | | `worksheet['!merges']` | 设置 Excel 中的合并单元格 | --- ### ✅ 输出效果(Excel) | 个人信息 | 成绩信息 | |----------------|--------------| | 年龄 | 城市 | 语文 | 数学 | | 25 | 北京 | 88 | 92 | | 27 | 上海 | 76 | 98 | 其中“个人信息”跨两列合并,“成绩信息”也跨两列。 --- ### ✅ 注意事项 - 如果表头超过两层(比如三级),需要递归处理并生成更多行。 - 当前方案适用于中小型数据量导出(千行以内)。大数据建议使用流式导出或后端服务。 - 可扩展支持样式、冻结窗格、数字格式等高级特性。 --- ### ✅ 相关优化方向 - 抽离成通用组件 `DynamicTableExporter` - 支持自定义导出字段过滤 - 支持时间格式、金额格式自动识别 - 添加 loading 错误提示 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值