
demo.png
<div id="app">
<el-table :data="tableData" border size="mini" :span-method="tableSpanMethod">
<el-table-column align="center" prop="index1" label="一级指标"></el-table-column>
<el-table-column align="center" prop="index2" label="二级指标"></el-table-column>
<el-table-column align="center" prop="index3" label="三级指标"></el-table-column>
</el-table>
</div>
<script>
export default {
data(){
return {
tableData:[],
testData:[{
id: '1',
label: '国土空间',
children: [{
id: '1-1',
label: '自然保护地面积占陆域国土面积比例(%)',
children: []
},{
id: '1-2',
label: '生态保护红线面积比例(%)',
children: []
},{
id: '1-3',
label: '森林覆盖率(%)',
children: []
},{
id: '1-4',
label: '林地蓄积量(万立方米)',
children: []
},{
id: '1-5',
label: '水土保持率(%)',
children: []
},{
id: '1-6',
label: '湿地保护率(%)',
children: []
}]
},{
id: '2',
label: '生态环境',
children: [{
id: '2-1',
label: '空气质量',
children: [{
id: '2-1-1',
label: '细微颗粒(PM2.5)浓度(微克/立方米)',
children: []
},{
id: '2-1-2',
label: '可吸入颗粒物(PM10)浓度(微克/立方米)',
children: []
}, {
id: '2-1-3',
label: '细微颗粒(PM2.5)浓度(微克/立方米)',
children: []
}]
},{
id: '2-2',
label: '水质质量',
children: [{
id: '2-2-1',
label: '饮用水水源地水质达标率',
children: []
},{
id: '2-2-2',
label: '地表水水质优良(达到或优于III类)比例(%)',
children: []
}]
},{
id: '2-3',
label: '受污染耕地安全利用率(%)',
children: []
},{
id: '2-4',
label: '湿地保护率(%)',
children: []
},{
id: '2-5',
label: '农业投入品使用',
children: [{
id: '2-5-1',
label: '农膜回收率(%)',
children: []
},{
id: '2-5-2',
label: '化肥利用率(%)',
children: []
},{
id: '2-5-3',
label: '农药利用率(%)',
children: []
}]
}]
},{
id: '3',
label: '地理信息',
children: []
}],
getMaxFloorNum: 0,
}
},
mounted() {
// 需要一个有且只有一个根节点的数据(如果返回的数据有且只有一个根节点,可省略此步骤)
let obj = {
id: '',
label: '',
children: this.testData
}
// 将 树结构数据 格式化为二维数组
let formatArr = this.parseTreeToRow(obj);
// console.log(formatArr)
// 再将其格式化为一维数组(ElementUi 表格所需要的数据格式)
let tableData = [];
if (formatArr[0].length != 0) {
formatArr.map((item, index) => {
let pushObj = { number : index + 1 }; // 添加索引值(列 序号),如不需要,则设置为空对象
item.map((itemb, indexb) => {
// 动态添加 指标列数据 对应 表头 prop 属性值
pushObj['index' + (indexb + 1)] = itemb.label;
// 添加 表格行数据 id (取的是最后一个children的 id 值)
if (indexb == item.length - 1) {
pushObj.id = itemb.id;
};
});
tableData.push(pushObj)
});
}
// console.log(tableData)
// 获取树结构最深层级数
this.getMaxFloorNum = this.getMaxFloor(this.testData);
// 未达到最深层级数节点 补充数据空缺
for (let i = 0; i < tableData.length; i++) {
for (let j = 0; j < this.getMaxFloorNum; j++) {
if (tableData[i]['index' + (j + 1)] == undefined) {
tableData[i]['index' + (j + 1)] = tableData[i]['index' + j];
}
}
}
// console.log(tableData)
this.tableData = tableData;
},
created() {
},
methods:{
/**
* 合并行或列的计算方法
*/
tableSpanMethod({row, column, rowIndex, columnIndex}){
return {
rowspan: this.mergeRows(row[column.property], this.tableData, rowIndex, column.property),
colspan: columnIndex > 0 ? this.mergeCells(row[column.property], row, column.property, this.getMaxFloorNum) : 1
};
},
/**
* 递归-----将树结构数据格式,转化为 二维数组 表格形式
* @param node 树的源数据
* @param data 树转化为二维数组的数据
* @param row 临时存储数据
* @returns {*[]}
*/
parseTreeToRow(node, data = [], row = []) {
if (node.children && node.children.length != 0) {
node.children.map((item, index) => {
const obj = {
id: item.id,
label: item.label,
};
this.parseTreeToRow(item, data, [...row, obj]);
});
} else {
data.push(row);
}
return data;
},
/**
* 递归-----树形数据(数组)获取最深层级数
* @param {Object} treeData 树的源数据
* @returns {Number} 最深层级数的值
*/
getMaxFloor(treeData) {
let floor = 0;
let max = 0;
let deepEach = (data, floor) => {
data.map((item, index) => {
item.floor = floor;
if (floor > max) {
max = floor;
};
if (item.children && item.children.length != 0) {
deepEach(item.children, floor + 1);
};
});
};
deepEach(treeData, 1);
return max;
},
/**
* 表格单元格合并-----行
* @param {Object} value 当前单元格的值
* @param {Object} data 当前表格所有数据
* @param {Object} index 当前单元格的值所在 行 索引
* @param {Object} property 当前列的property
* @returns {number} 待合并单元格数量
*/
mergeRows(value, data, index, property) {
// 判断 当前行的该列数据 与 上一行的该列数据 是否相等
if (index !== 0 && value === data[index - 1][property]) {
// 返回 0 使表格被跨 行 的那个单元格不会渲染
return 0;
};
// 判断 当前行的该列数据 与 下一行的该列数据 是否相等
let rowSpan = 1;
for (let i = index + 1; i < data.length; i++) {
if (value !== data[i][property]) {
break;
};
rowSpan++;
};
return rowSpan;
},
/**
* 表格单元格合并-----列
* @param {Object} value 当前单元格的值
* @param {Object} row 当前行数据
* @param {Object} property 当前列的property
* @param {Object} floorNum 二级指标的层级数
* @returns {number} 待合并单元格数量
*/
mergeCells(value, row, property, floorNum) {
// 取出当前 property 的尾数的 数字值
let index = Number(property.substring(5));
// 判断 当前行的该列数据 与 上一列数据 是否相等 (由于 “一级指标” 列不参与跨列,“二级指标” 列开始参与跨列,所以判断 property !== 'index2')
if(property !== 'index2' && value === row['index' + (index - 1)]){
// 返回 0 使表格被跨 列 的那个单元格不会渲染
return 0;
}
// 判断当前行的该列数据 与 下一列数据 是否相等
let colSpan = 1;
for(let i = index; i < floorNum; i++){
if(value !== row['index' + (index + 1)]){
break;
}
colSpan++;
}
return colSpan;
}
}
}
</script>
网友评论