theme: smartblue
前言
需求场景:
在提供了数据查看和修改的表格视图中(如table、a-table等…),允许用户自行选择多行数据,依据当前状态进行特定列数据的合并操作。选中的数据将统一显示为选中组的首条数据值。同时,页面会即时反馈显示合并后的效果,提供直观的操作反馈。
效果
方案选型
依赖库:vxe-table(:merge-cells="mergeCells"用作效果展示)
核心逻辑
根据数据行中的mergeId是否相等判断是否有过合并操作,前端执行合并操作后需将合并的数据的mergeId设置为相同的数值,并将选中数据中需要合并的数据项置为第一行选中的数据,并在页面展示合并后的效果。
保证两个一致:
- 数据一致性(数据覆盖) 优先级:极高
- 展示一致性(根据mergeId调整展示) 优先级:高
数据源举例
描述: 常规的后端返回结构,数组对象,数组中每一项指代每一条数据。
列表数据示例:
data:[
{mergeId:1,...},
{mergeId:2,...},
{mergeId:3,...}
]
合并逻辑:
- 数据一致性
coverParams:需要覆盖的参数名,存在于列表数据中
firstData:第一条数据
selectRows:选中的数据集合
coverParams.forEach(item => {
for (let i = 1; i < number; i++) {
// 选中的数据都覆盖第一条数据的值
selectRows[i][item] = firstData[item];
// }
}
});
- 展示一致性
newCurrentRows:由于选择时的随机性和数据结构的不稳定性,记录点击的位置点,并将位置点排序记录。
// 生成正序数组newCurrentRows
const newCurrentRows = currentRows.sort((a, b) => a - b);
// 若newCurrentRows数据不连续 则将选中数据都置为队尾
const isEqual = newCurrentRows.every((value, index, array) => {
if (index === 0) {
return true;
} else {
return value === array[index - 1] + 1;
}
})
情况1:选中的数据连续
coverCols:需要合并的行号组,字段的展示位置,用作生成mergeCells
firstRow:第一行位置
number:对应rowspan,得到跨几行的数据
// 获取选中了几条数据
const number = state.selectRows.length;
// 取第一个行号
const firstRow = newCurrentRows[0];
if (isEqual) {
const mergeCellsArr = [];
coverCols.forEach(item => {
mergeCellsArr.push({
row: firstRow,
col: item,
rowspan: number,
colspan: 1
});
});
mergeCells.value = mergeCellsArr;
}
情况2:选中的数据不连续
核心处理:将不连续的数据处理取出放置队尾,满足连续条件继续操作。
// 非选中的数据
const fristElements = [];
// 选中的数据集合
const secondElements = [];
// // 选中的数据置于队尾
// // 遍历原始数组
const dataNumber = dataSource.value.length;
for (let i = 0; i < dataNumber; i++) {
// 如果i在 newCurrentRows中不存在,则将其置于fristElements前列
if (!newCurrentRows.includes(i)) {
fristElements.push(dataSource.value[i]);
}
// // 如果i在 newCurrentRows中存在,则将其置于fristElements后列
if (newCurrentRows.includes(i)) {
secondElements.push(dataSource.value[i]);
}
}
const newSecondElements = secondElements.map(item => {
return {
...item
};
});
// 将新数组的元素追加到原始数组的末尾
dataSource.value = fristElements.concat(newSecondElements);
存在合并标识的数据处理
主要用作数据中存在mergeId标记如何展示合并效果。
// 初始数据根据mergeId组装合并效果
const baseDataMerge = () => {
// coverCols 需要合并的列号 注塑全新
const baseCoverCols = getCoverCols();
// length 需要合并的行数
const mergedCells = [];
dataSource.value.forEach((row, rowIndex) => {
//检查当前行的mergeId是否和下一行的mergeId一样 且mergeId存在
if (
rowIndex < dataSource.value.length - 1 &&
row.mergeId === dataSource.value[rowIndex + 1].mergeId &&
row.mergeId !== undefined
) {
// 仅在第一次符合条件时 判断横跨几行 默认跨两行
if (
dataSource.value[rowIndex + 3] &&
row.mergeId === dataSource.value[rowIndex + 3].mergeId
) {
// 横跨3行
state.mergeLength = 4;
} else if (
dataSource.value[rowIndex + 2] &&
row.mergeId === dataSource.value[rowIndex + 2].mergeId
) {
// 横跨4行
state.mergeLength = 3;
} else {
// 横跨2行
state.mergeLength = 2;
}
baseCoverCols.forEach(item => {
mergedCells.push({
row: rowIndex, // 开始行,由符合条件的
rowspan: state.mergeLength, // 合并行数,由选中的数据条数决定
col: item,
colspan: 1
});
});
state.mergeFlag = true;
}
});
console.log('初始数据合并效果', mergedCells);
return mergedCells;
};