背景
接了个外快需要在表格实现以下效果:
查文档
element文档中有“合并行或列”的例子: 多行或多列共用一个数据时,可以合并行或列。
通过给 table 传入span-method方法可以实现合并行或列, 方法的参数是一个对象,里面包含当前行 row、当前列 column、当前行号 rowIndex、当前列号 columnIndex 四个属性。 该函数可以返回一个包含两个元素的数组,第一个元素代表 rowspan,第二个元素代表 colspan。 也可以返回一个键名为 rowspan 和 colspan 的对象。
<template>
<div>
<el-table
:data="tableData"
:span-method="objectSpanMethod"
border
style="width: 100%; margin-top: 20px"
>
<el-table-column prop="id" label="ID" width="180" />
<el-table-column prop="name" label="Name" />
<el-table-column prop="amount1" label="Amount 1" />
<el-table-column prop="amount2" label="Amount 2" />
<el-table-column prop="amount3" label="Amount 3" />
</el-table>
</div>
</template>
<script lang="ts" setup>
import type { TableColumnCtx } from 'element-plus'
interface User {
id: string
name: string
amount1: string
amount2: string
amount3: number
}
interface SpanMethodProps {
row: User
column: TableColumnCtx<User>
rowIndex: number
columnIndex: number
}
const objectSpanMethod = ({
row,
column,
rowIndex,
columnIndex,
}: SpanMethodProps) => {
if (columnIndex === 0) {
if (rowIndex % 2 === 0) {
return {
rowspan: 2,
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
}
}
const tableData: User[] = [
{
id: '12987122',
name: 'Tom',
amount1: '234',
amount2: '3.2',
amount3: 10,
},
{
id: '12987123',
name: 'Tom',
amount1: '165',
amount2: '4.43',
amount3: 12,
},
{
id: '12987124',
name: 'Tom',
amount1: '324',
amount2: '1.9',
amount3: 9,
},
{
id: '12987125',
name: 'Tom',
amount1: '621',
amount2: '2.2',
amount3: 17,
},
{
id: '12987126',
name: 'Tom',
amount1: '539',
amount2: '4.1',
amount3: 15,
},
]
</script>
结合例子与具体需求分析
官方给的例子核心代码其实是这个:
const objectSpanMethod = ({
row,
column,
rowIndex,
columnIndex,
}: SpanMethodProps) => {
if (columnIndex === 0) {
if (rowIndex % 2 === 0) {
return {
rowspan: 2,
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
}
}
上面代码的意思就是: 当行数为偶数行(rowIndex % 2 === 0)时,合并第一列(columnIndex === 0)的当前行(rowIndex)和下一奇数行(rowspan: 2)
- rowspan用来指定单元格纵向跨越的行数:rowspan=2就是合并两行。
- colspan用来指定单元格横向跨越的列数:colspan=2就是合并两列。
这个列子和我的需求差距有点大。。。。。我的项目需求是:当设备,检测人等属性相同时,合并相同的行对应属性的列。
代码
多说无益直接上研究出来的代码(删除了部分属性,简化代码)
<script setup name="Reportdetail" lang="ts">
import type { TableColumnCtx } from 'element-plus'
import { ReportFormsService } from '@/api/analysis'
interface ReportDetail {
deviceName: string
userName: string
value1: string
value2: string
value3: string
value4: string
value5: string
detectionTime: string
groups: string
}
//需要判断的属性组
const spanProps = [
'deviceName',
'userName',
'detectionTime',
'groups',
]
interface SpanMethodProps {
row: ReportDetail
column: TableColumnCtx<ReportDetail>
rowIndex: number
columnIndex: number
}
let rowSpansMap = new Map() //存需要开始合并的行号,向下合并多少行
/**
* 根据列表数据得出需要合并的行
* @param data 列表数据
*/
const spanPropGroup = (data: any) => {
let oldRow = null //需要合并的行
rowSpansMap = new Map() //重置Map
oldRow = data[0] //默认第0行为需要合并的行
rowSpansMap.set(0, 1) //第0行,向下合并一行(其实就是自己单独一行)
let spanRow = 0 //记录需要开始合并的行号
for (let i = 1; i < data.length; i++) {
const item = data[i]
let isSame = true
//遍历需要判断的属性判断对应值是否全部相等
for (let j = 0; j < spanProps.length; j++) {
const prop = spanProps[j]
//只要有一个属性值不相等则记录新的需要合并的行号
if (item[prop] != oldRow[prop]) {
oldRow = item
rowSpansMap.set(i, 1)
spanRow = i
isSame = false
break
}
}
//如果所有属性值相同则所需要合并的行数+1
if (isSame) {
let span = rowSpansMap.get(spanRow)
rowSpansMap.set(spanRow, span + 1)
}
}
}
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
//采样值1-5列所对应的行不需要合并
if (
columnIndex != 8 &&
columnIndex != 9 &&
columnIndex != 10 &&
columnIndex != 11 &&
columnIndex != 12
) {
//根据当前行号从map中获取开始合并的行号,向下合并多少行
const span = rowSpansMap.get(rowIndex)
if (span != null) {
return {
rowspan: span,//向下合并span行
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
}
}
const route = useRoute()
const listLoading = ref(false)
const list = ref([])
//请求数据接口类(需继承ListAPI)
const listApi = new ReportFormsService()
const search = async (collectId: any) => {
list.value = []
listLoading.value = true
try {
const res = await listApi.listDetail(collectId)
const { code, data } = res
if (code == 200 && data) {
//根据列表数据得出需要合并的行
spanPropGroup(data)
list.value = data
}
} catch (error) {
console.log('🚀 ~ file: index.vue:73 ~ search ~ error:', error)
}
listLoading.value = false
}
search(route.params && route.params.collectId)
</script>
html代码
<template>
<el-container class="app-container">
<el-main>
<el-table v-loading="listLoading" :data="list" :span-method="objectSpanMethod">
<el-table-column label="设备" align="center" prop="deviceName" show-overflow-tooltip />
<el-table-column label="检测人" align="center" prop="userName" show-overflow-tooltip />
<el-table-column
label="工作面厚度差值"
align="center"
prop="workFaceThicknessDiff"
show-overflow-tooltip
/>
<el-table-column
label="锟端-工作面"
align="center"
prop="workFaceRollerEnd"
show-overflow-tooltip
/>
<el-table-column label="整体均值" align="center" prop="overallMean" show-overflow-tooltip />
<el-table-column
label="工作面中值"
align="center"
prop="workFaceMidValue"
show-overflow-tooltip
/>
<el-table-column
label="工作面最大值"
align="center"
prop="workFaceMaxValue"
show-overflow-tooltip
/>
<el-table-column
label="工作面最小值"
align="center"
prop="workFaceMinValue"
show-overflow-tooltip
/>
<el-table-column label="取样点1(mm)" align="center" prop="value1" show-overflow-tooltip />
<el-table-column label="取样点2(mm)" align="center" prop="value2" show-overflow-tooltip />
<el-table-column label="取样点3(mm)" align="center" prop="value3" show-overflow-tooltip />
<el-table-column label="取样点4(mm)" align="center" prop="value4" show-overflow-tooltip />
<el-table-column label="取样点5(mm)" align="center" prop="value5" show-overflow-tooltip />
<el-table-column
label="检测时间"
align="center"
prop="detectionTime"
show-overflow-tooltip
/>
<el-table-column label="班组" align="center" prop="groups" show-overflow-tooltip />
<el-table-column label="班次" align="center" prop="classes" show-overflow-tooltip />
</el-table>
</el-main>
</el-container>
</template>