原型图

分析

先看内容是三个表,每个表的合并单元格都有点不同。
按照原型图给的内容,第一个是两列,有行合并和列合并,还有表头行合并。
现根据图造出mock数据,然后再写对应的代码。

export const columnVarsData = {spanArr0: [{rowIndex: 3,columnIndex: 0,rowspan: 3,colspan: 1},{rowIndex: 0,columnIndex: 0,rowspan: 1,colspan: 2},{rowIndex: 1,columnIndex: 0,rowspan: 1,colspan: 2},{rowIndex: 2,columnIndex: 0,rowspan: 1,colspan: 2},{rowIndex: 6,columnIndex: 0,rowspan: 1,colspan: 2},{rowIndex: 7,columnIndex: 0,rowspan: 1,colspan: 2}],spanArr1: [{rowIndex: 0,columnIndex: 0,rowspan: 1,colspan: 2},{rowIndex: 1,columnIndex: 0,rowspan: 1,colspan: 2},{rowIndex: 3,columnIndex: 0,rowspan: 1,colspan: 2},{rowIndex: 4,columnIndex: 0,rowspan: 1,colspan: 2}],spanArr2: [{rowIndex: 0,columnIndex: 0,rowspan: 1,colspan: 2},{rowIndex: 1,columnIndex: 0,rowspan: 1,colspan: 2},{rowIndex: 2,columnIndex: 0,rowspan: 1,colspan: 2}],tableData: [{title: '汽车',columnList: [{appName: '汽车1',excessive: '汽车1',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '汽车2',excessive: '汽车2',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '汽车3',excessive: '汽车3',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '银行',excessive: '中国银行',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '银行',excessive: '华夏银行',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '银行',excessive: '农业银行',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '汽车中心',excessive: '汽车中心',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '汽车小计',excessive: '汽车小计',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60}],list: [{label: '数据',prop: 'appName'},{label: '数据',prop: 'excessive'},{label: '昨天',prop: 'yesterdayPendingReview'},{label: '今天',prop: 'newAddedToday'},{label: '明天',prop: 'currentAuditCirculation'},{label: '后天',prop: 'rejectionVolumeToday'},{label: '大后天',prop: 'remainingQuantityReview'}]},{title: '卡车',columnList: [{appName: '卡车1',excessive: '卡车1',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '卡车2',excessive: '卡车2',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '卡车3',excessive: '卡车4',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '小计',excessive: '小计',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '合计',excessive: '合计',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60}],list: [{label: '数据',prop: 'appName'},{label: '数据',prop: 'excessive'},{label: '昨天',prop: 'yesterdayPendingReview'},{label: '今天',prop: 'newAddedToday'},{label: '明天',prop: 'currentAuditCirculation'},{label: '后天',prop: 'rejectionVolumeToday'},{label: '大后天',prop: 'remainingQuantityReview'}]},{title: '出租车',columnList: [{appName: '出租车1',excessive: '出租车1',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '出租车2',excessive: '出租车2',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60},{appName: '出租车3',excessive: '出租车3',yesterdayPendingReview: 20,newAddedToday: 30,currentAuditCirculation: 40,rejectionVolumeToday: 50,remainingQuantityReview: 60}],list: [{label: '数据',prop: 'appName'},{label: '数据',prop: 'excessive'},{label: '昨天',prop: 'yesterdayPendingReview'},{label: '今天',prop: 'newAddedToday'},{label: '明天',prop: 'currentAuditCirculation'},{label: '后天',prop: 'rejectionVolumeToday'},{label: '大后天',prop: 'remainingQuantityReview'}]}]}

代码实现

<div v-for="(table, idx) in tableData"><el-tablesize="medium":data="table.columnList"v-tableFithighlight-current-row:stripe="false"ref="table"id="table"v-if="!loading"v-loading="loading":span-method="param => {return tableSpanMethod(param, idx)}":header-cell-style="handerMethod":row-class-name="tableRowClassName"><el-table-columnv-for="(column, columIndex) in table.list.slice(0, 2)":key="columIndex":prop="column.prop":label="column.label"align="center":index="columIndex"show-overflow-tooltip><template slot-scope="{ row, $index }"><span>{{ row[column.prop] }}</span></template></el-table-column><el-table-column :label="table.title" align="center"><el-table-columnv-for="(column, columIndex) in table.list.slice(2, 7)":key="columIndex":prop="column.prop":label="column.label"align="center":index="columIndex"show-overflow-tooltip><template slot-scope="{ row, $index }"><span>{{ row[column.prop] }}</span></template></el-table-column></el-table-column></el-table></div>
//导入mock数据import * as dict from './index.js'data() {return {loading: false,spanArr0: dict.columnVarsData.spanArr0,spanArr1: dict.columnVarsData.spanArr1,spanArr2: dict.columnVarsData.spanArr2,tableData: dict.columnVarsData.tableData}}methods: {//隐藏表头handerMethod({ row, column, rowIndex, columnIndex }) {if (row[0].level == 1) {//这里有个非常坑的bug 必须是row[0]=0 row[1]=2才会生效row[0].colSpan = 0row[1].colSpan = 2if (columnIndex === 0) {return { display: 'none' }}}},//单元格合并tableSpanMethod({ row, column, rowIndex, columnIndex }, idx) {const span = `spanArr${idx}`const spanArr = this[span]for (let i = 0; i < spanArr.length; i++) {//划分出需合并的每一个区域(spanArr[i])if (columnIndex >= spanArr[i].columnIndex &&columnIndex <= spanArr[i].columnIndex + spanArr[i].colspan - 1 &&rowIndex >= spanArr[i].rowIndex &&rowIndex <= spanArr[i].rowIndex + spanArr[i].rowspan - 1) {// 保留展示的单元格,合并单元格都为向右与向下延伸if (columnIndex === spanArr[i].columnIndex &&rowIndex === spanArr[i].rowIndex) {return {rowspan: spanArr[i].rowspan,colspan: spanArr[i].colspan}} else {//删除冗余单元格return {rowspan: 0,colspan: 0}}}}},}

效果


——————————————————— 手动分割线 ———————————————–

目前spanArr0、spanArr1、spanArr2是写死的,如果后端返回的输入不固定的话,那个还要挨个去改,所以手动写个方法。可自行优化方法

data() {return {loading: false,spanArr0: [],spanArr1: [],spanArr2: [],tableData: dict.columnVarsData.tableData,}}created() {this.spanArr0 = this.handleList(this.tableData[0].columnList)this.spanArr1 = this.handleList(this.tableData[1].columnList)this.spanArr2 = this.handleList(this.tableData[2].columnList)},methods: {//处理数据行列单元格handleList(list) {let name = ''let arr = []let ownidx = 0for (let i = 0; i < list.length; i++) {//如果这两个字段相同取出行坐标放在数组里if (list[i].appName == list[i].excessive) {let rowObj = {rowIndex: i,columnIndex: 0,rowspan: 1,colspan: 2}arr.push(rowObj)} else {list[i]['count'] = 0name = list[i].appName//如果数据不同看数组里appName相同的有几条数据const arrList = this.countKeywords(list, name)let idx = arrList.findIndex(item => item.appName === name)ownidx = idxlet colObj = {rowIndex: idx,columnIndex: 0,rowspan: arrList[idx]['count'],colspan: 1}arr.push(colObj)}}arr = this.countIdxwords(arr, ownidx)return arr},//获取appName相同的数据countKeywords(array, appName) {for (let j = 0; j < array.length; j++) {let k = 'appName'if (array[j][k] != appName) array[j]['count'] = 1else array[j]['count'] += 1}return array},//最后处理数据,合并行countIdxwords(arr, idx) {//第一步,去重var hash = []for (var i = 0; i < arr.length; i++) {for (var j = i + 1; j < arr.length; j++) {if (arr[i].rowIndex === arr[j].rowIndex) {++ij = i}}arr[i].num = 0hash.push(arr[i])}// 第二步,统计重复个数hash.forEach(item => {arr.forEach(dd => {if (item.rowIndex === dd.rowIndex) {item.num++}})})console.log(hash, '===>hash')return hash}}

看一下改好的效果

没啥变化