关于表格合并span-method方法的补充(表格数据由后台动态返回)
之前写了一些关于element-ui表格合并的方法,不过用的数据都是确定的数据(死数据),但是很多时候我们的数据都是通过后台获得的,数据不稳定,这个时候使用表格合并就需要先处理一下数据,先看一下一种很常见的数据展示场景
本博客源码: https://github.com/shengbid/vue-demo 这个项目里会把平时博客写的一些功能的代码都放在里面,有需要可以下载看看,有帮助的话点个star哈
直接上代码,HTML代码就不放了,都是差不多的,下面另一种场景有
// 模拟后台返回的值 getTable () { this.tableData = [{ id: 1, region: '中国', type: [{ sortName: '器械', sortList: [{ name: '器械1' }, { name: '器械2' }] }, { sortName: '软件', sortList: [{ name: '软件1' }, { name: '软件2' }, { name: '软件3' }] }] }, { id: 2, region: '美国', type: [{ sortName: '器械', sortList: [{ name: '器械1' }, { name: '器械2' }] }, { sortName: '软件', sortList: [{ name: '软件1' }, { name: '软件2' }] }] }] this.dealTable() }, // 处理表格数据 dealTable () { let getDate = [] // 存储新表格数据 let typeIndex = [0] // 保存id,地区需要合并的值 let nameIndex = [0] // 保存类型需要合并的值 let a // id,地区需要合并的行是所有类型的长度 this.tableData.forEach((v, index) => { if (v.type && v.type.length) { a = 0 v.type.forEach((subV, i, typeData) => { if (subV.sortList && subV.sortList.length) { subV.sortList.forEach((ss, k, data) => { if (k === data.length - 1) { typeIndex.push(data.length) // 把每一个类型下面数据长度存起来 a += data.length // 把所有类型下面的数据长度相加 if (i === typeData.length - 1) { nameIndex.push(a) // 类型循环完成后把数据长度存起来 } } getDate.push({ id: v.id, region: v.region, type: subV.sortName, name: ss.name }) }) } }) } }) console.log(nameIndex) // [0, 5, 4] // 看一下打印出来的规律,除去第一项,5是第一次需要合并的行 // 第二次合并又是从第五行开始合并4行 console.log(typeIndex) // [0, 2, 3, 2, 2] // 类型的数据存储规律也是一样,第一次合并2行 // 第二次从2行开始,合并3行,以此类推 // 根据这个规则,只需要给数据加上两个额外的属性控制是否合并就OK let k = 0 let t = 0 nameIndex.forEach((v, i, nameArr) => { if (nameArr[i + 1]) { getDate[k].nameIndex = nameArr[i + 1] k += nameArr[i + 1] } }) typeIndex.forEach((v, i, typeArr) => { if (typeArr[i + 1]) { getDate[t].typeIndex = typeArr[i + 1] t += typeArr[i + 1] } }) this.tableData6 = getDate console.log(getDate) // 0: {id: 1, name: "器械1", nameIndex: 5, region: "中国", type: "器械", typeIndex: 2}, // 1: {id: 1, name: "器械2", region: "中国", type: "器械"} // .... // 5: {id: 2, name: "器械1", nameIndex: 4, region: "美国", type: "器械", typeIndex: 2} }, // 表格合并方法 arraySpanMethod ({ row, column, rowIndex, columnIndex }) { if (columnIndex === 0 || columnIndex === 1) { if (row.nameIndex) { // 如果有值,说明需要合并 return [row.nameIndex, 1] } else return [0, 0] } if (columnIndex === 2) { if (row.typeIndex) { return [row.typeIndex, 1] } else return [0, 0] } },
再说一下另一种场景,用的另一种方法实现,原理都是大同小异
假设后台返回的数据是这样的:
在这种情况下,一般我们会选择对行进行合并,因为这时候表格的列是知道的,只要把需要合并的列提取出来,合并行就OK,下面看代码
HTML代码
<el-table :data="tableData6" :span-method="arraySpanMethod" border style="width: 100%"> <el-table-column prop="id" label="ID" width="180"> </el-table-column> <el-table-column prop="region" label="深圳"> </el-table-column> <el-table-column prop="type" label="类型"> </el-table-column> <el-table-column prop="company" label="企业名称"> </el-table-column> </el-table>
js代码,首先需要处理一下后台数据
getIndex () { let arr = [] let s = 0 let table = this.tableData6 let getTable = [] table.forEach((item, i, data) => { if (arr.length) { s = arr[arr.length - 1].row + data[i - 1].company.length } arr.push({ row: s, index: item.company.length }) if (item.company && item.company.length) { item.company.forEach(subItem => { getTable.push({ id: item.id, region: item.region, type: item.type, company: subItem.name }) }) } }) this.arr = arr this.tableData6 = getTable },
数据处理之后就进行表格合并
// 合并表格方法 arraySpanMethod ({ row, column, rowIndex, columnIndex }) { if (columnIndex === 0 || columnIndex === 1 || columnIndex === 2) { let obj = [0, 0] this.arr.some(v => { if (rowIndex === v.row) { obj = [v.index, 1] } }) return obj } }
PS: 在这里说一下楼主遇到的一个坑,其实也是因为对函数的return不熟悉造成的,一开始我是这样写的,
结果页面一直不对,debugger了一下,发现函数中根本没接收到return回去的数据,这是因为我return之后又写了代码,函数真正结束时没有返回值.所以在函数中,return之后就不要在写执行代码了.
正确的写法后debugger就能接收到正确的返回值了
补充内容:
后面自己又整理了一下,写了一个公共方法,可以处理两层合并和三层合并,完整代码,这是一个完整的vue代码,可以直接复制到代码中看效果
<template> <div style="padding:30px;"> <h2>后台返回数据动态合并(根据后台返回的数据进行表格合并)</h2> <p> 两层数据合并 </p> <el-table :data="tableData2" :span-method="arraySpanMethod2" border style="width: 100%;" > <el-table-column prop="id" label="ID" width="180" /> <el-table-column prop="region" label="地区" /> <el-table-column prop="type" label="类型" /> </el-table> <!-- 表格2 --> <p style="margin-top: 40px"> 三层数据合并 </p> <el-table :data="tableData" :span-method="arraySpanMethod" border style="width: 100%" > <el-table-column prop="id" label="ID" width="180" /> <el-table-column prop="region" label="地区" /> <el-table-column prop="type" label="类型" /> <el-table-column prop="name" label="产业" /> </el-table> </div> </template> <script> export default { data() { return { tableData: [], tableData2: [] } }, created() { this.getTable() }, methods: { getTable() { const tableData = [{ id: 1, region: '中国', type: [{ sortName: '器械', sortList: [{ name: '器械1' }, { name: '器械2' }] }, { sortName: '软件', sortList: [{ name: '软件1' }, { name: '软件2' }, { name: '软件3' }] }] }, { id: 2, region: '美国', type: [{ sortName: '器械', sortList: [{ name: '器械1' }, { name: '器械2' }] }, { sortName: '软件', sortList: [{ name: '软件1' }, { name: '软件2' }] }] }, { id: 3, region: '加拿大', type: [{ sortName: '器械', sortList: [{ name: '器械1' }] }] }] this.dealTable(tableData) this.dealTable(tableData, 2) }, // 处理表格数据(level,表格合并的层级) dealTable(tableData, level = 3) { const getDate = [] // 存储新表格数据 let a // id,地区需要合并的行是所有类型的长度 tableData.forEach((v, index) => { if (v.type && v.type.length) { a = 0 v.type.forEach((subV, i, typeData) => { if (level === 2) { // 处理两层合并数据 const obj = { id: v.id, region: v.region, type: subV.sortName } if (i === 0) { obj.typeIndex = typeData.length } getDate.push(obj) } else if (subV.sortList && subV.sortList.length) { subV.sortList.forEach((ss, k, data) => { const obj = { id: v.id, region: v.region, type: subV.sortName, name: ss.name } if (k === 0) { obj.typeIndex = data.length } getDate.push(obj) if (k === data.length - 1) { a += data.length // 把所有类型下面的数据长度相加 if (i === typeData.length - 1) { getDate[getDate.length - a ].nameIndex = a } } }) } }) } }) if (level === 2) { this.tableData2 = getDate } else { this.tableData = getDate } console.log(getDate) // 0: {id: 1, name: "器械1", nameIndex: 5, region: "中国", type: "器械", typeIndex: 2}, // 1: {id: 1, name: "器械2", region: "中国", type: "器械"} // .... // 5: {id: 2, name: "器械1", nameIndex: 4, region: "美国", type: "器械", typeIndex: 2} }, // 表格合并方法(三层数据) arraySpanMethod({ row, column, rowIndex, columnIndex }) { if (columnIndex === 0 || columnIndex === 1) { if (row.nameIndex) { // 如果有值,说明需要合并 return [row.nameIndex, 1] } else return [0, 0] } if (columnIndex === 2) { if (row.typeIndex) { return [row.typeIndex, 1] } else return [0, 0] } }, // 表格合并方法(两层数据) arraySpanMethod2({ row, column, rowIndex, columnIndex }) { if (columnIndex === 0 || columnIndex === 1) { if (row.typeIndex) { // 如果有值,说明需要合并 return [row.typeIndex, 1] } else return [0, 0] } } } } </script>
表格后边后默认只有合并部分的第一行鼠标移入高亮,如果有hover样式的需求可以看这一篇博客https://www.cnblogs.com/steamed-twisted-roll/p/10469887.html
补充内容:
如果表格的层级不确定,或者层级比较多,多次循环写的很麻烦,可以参考我最近整理的这篇,动态层级的表格合并,是一个通用的合并处理方法, 2-5级的表格合并都试验了没问题,其他更多层级的需求也可以用
children为空和不为空的情况也处理了
链接: https://www.cnblogs.com/steamed-twisted-roll/p/17109524.html