效果展示(示例)
前
后
合并单元格,为了样式好看,加上边框会更好看
案例一
<template>
<el-table :data="tableData" :span-method="objectSpanMethod" border>
<el-table-column prop="date" label="日期" width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" width="180">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData: [
{ date: '2023-05-02', name: '张三', address: '北京市朝阳区' },
{ date: '2023-05-02', name: '张三', address: '北京市海淀区' },
{ date: '2023-05-03', name: '李四', address: '上海市浦东新区' },
{ date: '2023-05-04', name: '王五', address: '广州市天河区' },
]
};
},
methods: {
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0 || columnIndex === 1) {
const prevRow = this.tableData[rowIndex - 1];
const currRow = row;
if (prevRow && prevRow[column.property] === currRow[column.property]) {
return { rowspan: 0, colspan: 0 };
} else {
let rowspan = 1;
for (let i = rowIndex + 1; i < this.tableData.length; i++) {
if (this.tableData[i][column.property] === currRow[column.property]) {
rowspan++;
} else {
break;
}
}
if (rowspan > 1) {
return { rowspan: rowspan, colspan: 1 };
}
}
}
}
}
};
</script>
案例二 推荐
<el-table :span-method="objectSpanMethod">
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
//定义需要合并的列字段,有哪些列需要合并,就自定义添加字段即可
const fields = ['companyIdTxt']
// 当前行的数据
const cellValue = row[column.property]
// 判断只合并定义字段的列数据
if (cellValue && fields.includes(column.property)) {
const prevRow = this.rowData[rowIndex - 1] //上一行数据
let nextRow = this.rowData[rowIndex + 1] //下一行数据
// 当上一行的数据等于当前行数据时,当前行单元格隐藏
if (prevRow && prevRow[column.property] === cellValue) {
return { rowspan: 0, colspan: 0 }
} else {
// 反之,则循环判断若下一行数据等于当前行数据,则当前行开始进行合并单元格
let countRowspan = 1 //用于合并计数多少单元格
while (nextRow && nextRow[column.property] === cellValue) {
nextRow = this.rowData[++countRowspan + rowIndex]
}
if (countRowspan > 1) {
return { rowspan: countRowspan, colspan: 1 }
}
}
}
},
注意:
当 fields 为空数组或列不在 fields 中时,它将返回一个对象,其中 rowspan 和 colspan 都设置为 1,这样可以确保不合并任何单元格:
// 如果fields为空数组或当前列不在fields中,则不进行合并
if (fields.length === 0) {
return { rowspan: 1, colspan: 1 };
}
vue3 实战
<template>
<el-table :data="tableData" :span-method="objectSpanMethod" border>
<el-table-column prop="date" label="日期" width="180">
</el-table-column>
<el-table-column prop="name" label="姓名" width="180">
</el-table-column>
<el-table-column prop="address" label="地址">
</el-table-column>
</el-table>
</template>
<script>
const tableData = ref( [
{ date: '2023-05-02', name: '张三', address: '北京市朝阳区' },
{ date: '2023-05-02', name: '张三', address: '北京市海淀区' },
{ date: '2023-05-03', name: '李四', address: '上海市浦东新区' },
{ date: '2023-05-04', name: '王五', address: '广州市天河区' },
])
function objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0 || columnIndex ===1 ) {
const prevRow = tableData.value[rowIndex - 1];
const currRow = row;
if (prevRow && prevRow[column.property] === currRow[column.property]) {
return { rowspan: 0, colspan: 0 };
} else {
let rowspan = 1;
for (let i = rowIndex + 1; i < tableData.value.length; i++) {
if (tableData.value[i][column.property] === currRow[column.property]) {
rowspan++;
} else {
break;
}
}
if (rowspan > 1) {
return { rowspan: rowspan, colspan: 1 };
}
}
}
}
</script>
function objectSpanMethod({ row, column, rowIndex, columnIndex }) {
//定义需要合并的列字段,有哪些列需要合并,就自定义添加字段即可
const fields = ['date','name']
// 当前行的数据
const cellValue = row[column.property]
// 判断只合并定义字段的列数据
if (cellValue && fields.includes(column.property)) {
const prevRow = tableData.value[rowIndex - 1] //上一行数据
let nextRow = tableData.value[rowIndex + 1] //下一行数据
// 当上一行的数据等于当前行数据时,当前行单元格隐藏
if (prevRow && prevRow[column.property] === cellValue) {
return { rowspan: 0, colspan: 0 }
} else {
// 反之,则循环判断若下一行数据等于当前行数据,则当前行开始进行合并单元格
let countRowspan = 1 //用于合并计数多少单元格
while (nextRow && nextRow[column.property] === cellValue) {
nextRow = tableData.value[++countRowspan + rowIndex]
}
if (countRowspan > 1) {
return { rowspan: countRowspan, colspan: 1 }
}
}
}
}
改进:限制分组内数据单元格合并
效果
说明:遇到相同值,不会合并,因为受到了组限制**
实现(容易理解)
function objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (unref(props.value?.spanMethodFields)?.length > 0) {
border.value = true;
// 定义需要合并的列字段
if (unref(props.value?.spanMethodFields).includes(column.property)) {
const cellValue = row[column.property];
// 新增:用于分组的字段
const groupField = props.value.groupField;
// 新增:获取当前行的分组值
const currentGroupValue = row[groupField];
const prevRow = tableDataRef.value[rowIndex - 1];
let nextRow = tableDataRef.value[rowIndex + 1];
// 修改:增加分组值的比较
if (prevRow && prevRow[groupField] === currentGroupValue && prevRow[column.property] === cellValue) {
return { rowspan: 0, colspan: 0 };
} else {
let countRowspan = 1;
// 修改:增加分组值的比较
while (nextRow && nextRow[groupField] === currentGroupValue && nextRow[column.property] === cellValue) {
countRowspan++;
nextRow = tableDataRef.value[rowIndex + countRowspan];
}
if (countRowspan > 1) {
return { rowspan: countRowspan, colspan: 1 };
}
}
}
}
return { rowspan: 1, colspan: 1 };
}
props: {
value: {
spanMethodFields: ['column1', 'column2'],
groupField: 'groupColumn'
}
}
代码实现(健壮性比较强-copy)
function objectSpanMethod({row, column, rowIndex, columnIndex}) {
if (unref(props.value?.spanMethodFields)?.length > 0) {
border.value = true;
//定义需要合并的列字段,有哪些列需要合并,就自定义添加字段即可
// 当前行的数据
const cellValue = row[column.property]
// 新增:用于分组的字段
const groupField = props.value.groupField;
// 新增:获取当前行的分组值
const currentGroupValue = row[groupField]
// 判断逻辑:如果有groupField,则考虑分组;否则只考虑单元格值
const isSameGroup = (row1, row2) =>
!groupField || (row1 && row2 && row1[groupField] === row2[groupField]);
// 修改:判断cellValue是否存在,包括0
const isCellValuePresent = cellValue !== undefined && cellValue !== null;
// 判断只合并定义字段的列数据(cellValue)
if (isCellValuePresent && unref(props.value?.spanMethodFields).includes(column.property)) {
const prevRow = tableDataRef.value[rowIndex - 1] //上一行数据
let nextRow = tableDataRef.value[rowIndex + 1] //下一行数据
// 当上一行存在,且(无分组或分组相同),且上一行的单元格值与当前行相同时,隐藏当前单元格
if (prevRow && prevRow[column.property] === cellValue && isSameGroup(prevRow, row)) {
return {rowspan: 0, colspan: 0}
} else {
// 向下查找连续相同(分组和单元格值)的行数
let countRowspan = 1 //用于合并计数多少单元格
while (nextRow && nextRow[column.property] === cellValue && isSameGroup(nextRow, row)) {
nextRow = tableDataRef.value[++countRowspan + rowIndex]
}
if (countRowspan > 1) {
return {rowspan: countRowspan, colspan: 1}
}
}
}
} else {
return {rowspan: 1, colspan: 1};
}
}
使用
- groupField
- spanMethodFields
<BasicTable @register="register" groupField="taskNum"
:spanMethodFields="['nodeTime','companyName','taskNum','eventDesc','stageContent','finalContent']">
上文仍存在一个问题:就是指定分组合并后,相同的null值无法进行合并(Copy)
效果:null值也能进行合并
function objectSpanMethod({row, column, rowIndex, columnIndex}) {
if (unref(spanMethodFields)?.length > 0) {
// 定义需要合并的列字段,有哪些列需要合并,就自定义添加字段即可
// 当前行的数据
const cellValue = row[column.property]
// 用于分组的字段
// 获取当前行的分组值
const currentGroupValue = row[groupField.value]
// 判断逻辑:如果有groupField,则考虑分组;否则只考虑单元格值
const isSameGroup = (row1, row2) =>
!groupField.value || (row1 && row2 && row1[groupField.value] === row2[groupField.value]);
// 判断cellValue是否相同,包括null
const isSameCellValue = (value1, value2) => value1 === value2;
// 判断只合并定义字段的列数据
if (unref(spanMethodFields).includes(column.property)) {
const prevRow = tableData.value[rowIndex - 1] // 上一行数据
let nextRow = tableData.value[rowIndex + 1] // 下一行数据
// 当上一行存在,且(无分组或分组相同),且上一行的单元格值与当前行相同时,隐藏当前单元格
if (prevRow && isSameCellValue(prevRow[column.property], cellValue) && isSameGroup(prevRow, row)) {
return {rowspan: 0, colspan: 0}
} else {
// 向下查找连续相同(分组和单元格值)的行数
let countRowspan = 1 // 用于合并计数多少单元格
while (nextRow && isSameCellValue(nextRow[column.property], cellValue) && isSameGroup(nextRow, row)) {
nextRow = tableData.value[++countRowspan + rowIndex]
}
if (countRowspan > 1) {
return {rowspan: countRowspan, colspan: 1}
}
}
}
}
return {rowspan: 1, colspan: 1};
}
主要的改进包括:
移除了 isCellValuePresent 检查,因为我们现在要允许 null 值也参与合并。
添加了 isSameCellValue 函数来比较单元格值,这个函数可以正确处理 null 值的比较。
在比较单元格值时,使用新的 isSameCellValue 函数替代了直接比较。
简化了函数结构,移除了多余的条件判断。
这些改动允许同一组内的 null 值也能被合并,同时保持了原有的功能。现在,无论单元格的值是什么(包括 null),只要它们在同一组内且连续相同,就会被合并。