原型图
分析
先看内容是三个表,每个表的合并单元格都有点不同。
按照原型图给的内容,第一个是两列,有行合并和列合并,还有表头行合并。
现根据图造出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-table
size="medium"
:data="table.columnList"
v-tableFit
highlight-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-column
v-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-column
v-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 = 0
row[1].colSpan = 2
if (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 = 0
for (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'] = 0
name = list[i].appName
//如果数据不同看数组里appName相同的有几条数据
const arrList = this.countKeywords(list, name)
let idx = arrList.findIndex(item => item.appName === name)
ownidx = idx
let 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'] = 1
else 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) {
++i
j = i
}
}
arr[i].num = 0
hash.push(arr[i])
}
// 第二步,统计重复个数
hash.forEach(item => {
arr.forEach(dd => {
if (item.rowIndex === dd.rowIndex) {
item.num++
}
})
})
console.log(hash, '===>hash')
return hash
}
}
看一下改好的效果
没啥变化