表格中,针对相同数据进行合并。这个时候,我们需要对表格进行处理。
1,最简单的合并,如下图:
2,稍微复杂的合并,如下图:
3,再稍微复杂的合并【增加了多选框】,如下图:
4,再稍微复杂的合并【增加了编辑单元格】,如下图:
【不难发现】这些表格,都是以某个维度(基础列),进行合并单元格的。比如,第4个图,根据“出库单号”进行合并的。就会出现了,“退货理由”这一栏,不会多行合并。
说这么多,现在上代码。
/**
* table合并行通用 */
export function mergeTableRow(config) {
let data = config.data
const { mergeColNames, firstMergeColNames, firstMerge } = config
if (!mergeColNames || mergeColNames.length === 0) {
return data
}
mergeColNames.forEach((m) => {
const mList = {}
data = data.map((v, index) => {
// 区分需要合并行的key的值
const rowVal = v[firstMerge] + '-' + v[m] // 【重点】
// 需要合并行的第二行以及之后行会走if
// m==firstMerge 判断需要合并的列是否是基准列,如果是则只满足前面的条件,如果不是则需要满足前面+后面的条件
if (mList[rowVal] && mList[rowVal].newIndex === index) {
const flag = firstMergeColNames.filter((f) => { return f === m }).length !== 0
const mcFlag = mergeColNames.filter((mc) => { return mc === firstMerge }).length === 0
if ((mcFlag && flag) || (flag && data[index][firstMerge + '-span'] && data[index][firstMerge + '-span'].rowspan === 1)) {
v[m + '-span'] = {
rowspan: 1,
colspan: 1
}
} else {
data[mList[rowVal].index][m + '-span'].rowspan++
v[m + '-span'] = {
rowspan: 0,
colspan: 0
}
mList[rowVal].num++
mList[rowVal].newIndex++
}
} else {
mList[rowVal] = { num: 1, index: index, newIndex: index + 1 }
v[m + '-span'] = {
rowspan: 1,
colspan: 1
}
}
return v
})
})
return data
}
<1> 还有另一个情况,因为没根据维度区分来进行合并单元格,如下图:
这个时候,如果不区分维度,只是简单的合并。
上述方法,【重点】处,改成: const rowVal = v[m]
注释掉:// const rowVal = v[firstMerge] + '-' + v[m]
针对单元格合并的时候,能进行批量选择:
思路:对列表数据进行处理,加个属性
// 获取列表
getList() {
// 添加属性 check 多选框
issue_records.map(v => {
v.check = v.saleNo
})
setTimeout(() => {
const mergeColNames = ['check', 'saleNo', 'orderType', 'status', 'issueNo', 'product', 'issueDate']
const firstMergeColNames = ['saleNo', 'issueNo']
const firstMerge = 'saleNo'
this.tableData = cellTableMerge(issue_records, mergeColNames, firstMergeColNames, firstMerge, 'check')
}, 500);
},
// 勾选逻辑
selectionChange(val) {
const arr = filterFn(val, this.tableData, 'saleNo')
this.printList = uniqueFn(arr, 'id')
},
rowSelect(rows, row) {
const flag = rows.length && rows.indexOf(row) !== -1 // 判断当前数据是否勾选
if (!flag) {
// 取消勾选
if (!this.tem.length) {
// 开始进来
this.tem = rows.filter(v => v.saleNo != row.saleNo)
} else {
// 再次取消勾选
this.tem = this.tem.filter(v => v.saleNo != row.saleNo)
}
setTimeout(() => {
this.printList = this.tem
}, 500);
}
},
/** 数组A根据某一属性对数组B进行筛选
* @param {目标数组} a
* @param {全量数组} b
* @param {变量} name
*/
filterFn(a, b, name) {
const temArr = []
a.forEach(item => {
b.forEach(ele => {
if (item[name] == ele[name]) {
temArr.push(ele)
}
})
})
return temArr
}
<2> 还有一点: 针对合并单元格+编辑,提交编辑后的数据给后端
思路:合并单元格后,点击某一行,进行编辑内容,提交数据的时候,发现有些合并项的数据(编辑)可能没值,这个时候需要获取,该合并的数据(数组),循环把编辑内容后的行数据的某个属性aa的xxx值,赋值到数组每一项的属性aa。
<3> 如果需要排序:
/**
* 排序
* 将传入的数组根据当前系统语言,按照中文或英文名重新排序,会影响原数组
* @param list 必填要排序的list
* @param key 必填 属性
* @param order 排列顺序 asc正序 desc倒序
* @returns {*}
*/
export function sortArray(list, key, order = 'asc') {
if (list === undefined || list === null) return []
list.sort((a, b) => {
const strA = order == 'asc' ? a[key] : b[key]
const strB = order == 'asc' ? b[key] : a[key]
// 谁为非法值谁在前面
if (strA === undefined || strA === null || strA === '' || strA === ' ' || strA === ' ') {
return -1
}
if (strB === undefined || strB === null || strB === '' || strB === ' ' || strB === ' ') {
return 1
}
// 如果a和b中全部都是汉字,或者全部都非汉字
if ((strA.split('').every(char => notChinese(char)) && strB.split('').every(char => notChinese(char))) ||
(strA.split('').every(char => !notChinese(char)) && strB.split('').every(char => !notChinese(char)))) {
return strA.localeCompare(strB)
} else {
const charAry = strA.split('')
for (const i in charAry) {
if ((charCompare(strA[i], strB[i]) !== 0)) {
return charCompare(strA[i], strB[i])
}
}
// 如果通过上面的循环对比还比不出来,就无解了,直接返回-1
return -1
}
})
return list
}
function charCompare(charA, charB) {
// 谁为非法值谁在前面
if (charA === undefined || charA === null || charA === '' || charA === ' ' || charA === ' ') {
return -1
}
if (charB === undefined || charB === null || charB === '' || charB === ' ' || charB === ' ') {
return 1
}
// 如果都为英文或者都为汉字则直接对比
if ((notChinese(charA) && notChinese(charB)) || (!notChinese(charA) && !notChinese(charB))) {
return charA.localeCompare(charB)
} else {
// 如果不都为英文或者汉字,就肯定有一个是英文,如果a是英文,返回-1,a在前,否则就是b是英文,b在前
if (notChinese(charA)) {
return -1
} else {
return 1
}
}
}
function notChinese(char) {
const charCode = char.charCodeAt(0)
return charCode >= 0 && charCode <= 128
}
<4> 最后,总体的代码,合并单元格 + 排序的代码,如下:
/**
* el-table 合并行通用 */
export function mergeTableRow(config) {
let data = config.data
const { mergeColNames, firstMergeColNames, firstMerge } = config
if (!mergeColNames || mergeColNames.length === 0) {
return data
}
mergeColNames.forEach((m) => {
const mList = {}
data = data.map((v, index) => {
// 区分需要合并行的key的值
// const rowVal = v[m]
const rowVal = v[firstMerge] + '-' + v[m]
// 需要合并行的第二行以及之后行会走if
// m==firstMerge 判断需要合并的列是否是基准列,如果是则只满足前面的条件,如果不是则需要满足前面+后面的条件
if (mList[rowVal] && mList[rowVal].newIndex === index) {
const flag = firstMergeColNames.filter((f) => { return f === m }).length !== 0
const mcFlag = mergeColNames.filter((mc) => { return mc === firstMerge }).length === 0
if ((mcFlag && flag) || (flag && data[index][firstMerge + '-span'] && data[index][firstMerge + '-span'].rowspan === 1)) {
v[m + '-span'] = {
rowspan: 1,
colspan: 1
}
} else {
data[mList[rowVal].index][m + '-span'].rowspan++
v[m + '-span'] = {
rowspan: 0,
colspan: 0
}
mList[rowVal].num++
mList[rowVal].newIndex++
}
} else {
mList[rowVal] = { num: 1, index: index, newIndex: index + 1 }
v[m + '-span'] = {
rowspan: 1,
colspan: 1
}
}
return v
})
})
return data
}
/**
* 排序
* 将传入的数组根据当前系统语言,按照中文或英文名重新排序,会影响原数组
* @param list 必填要排序的list
* @param key 必填 属性
* @param order 排列顺序 asc正序 desc倒序
* @returns {*}
*/
export function sortArray(list, key, order = 'asc') {
if (list === undefined || list === null) return []
list.sort((a, b) => {
const strA = order == 'asc' ? a[key] : b[key]
const strB = order == 'asc' ? b[key] : a[key]
// 谁为非法值谁在前面
if (strA === undefined || strA === null || strA === '' || strA === ' ' || strA === ' ') {
return -1
}
if (strB === undefined || strB === null || strB === '' || strB === ' ' || strB === ' ') {
return 1
}
// 如果a和b中全部都是汉字,或者全部都非汉字
if ((strA.split('').every(char => notChinese(char)) && strB.split('').every(char => notChinese(char))) ||
(strA.split('').every(char => !notChinese(char)) && strB.split('').every(char => !notChinese(char)))) {
return strA.localeCompare(strB)
} else {
const charAry = strA.split('')
for (const i in charAry) {
if ((charCompare(strA[i], strB[i]) !== 0)) {
return charCompare(strA[i], strB[i])
}
}
// 如果通过上面的循环对比还比不出来,就无解了,直接返回-1
return -1
}
})
return list
}
function charCompare(charA, charB) {
// 谁为非法值谁在前面
if (charA === undefined || charA === null || charA === '' || charA === ' ' || charA === ' ') {
return -1
}
if (charB === undefined || charB === null || charB === '' || charB === ' ' || charB === ' ') {
return 1
}
// 如果都为英文或者都为汉字则直接对比
if ((notChinese(charA) && notChinese(charB)) || (!notChinese(charA) && !notChinese(charB))) {
return charA.localeCompare(charB)
} else {
// 如果不都为英文或者汉字,就肯定有一个是英文,如果a是英文,返回-1,a在前,否则就是b是英文,b在前
if (notChinese(charA)) {
return -1
} else {
return 1
}
}
}
function notChinese(char) {
const charCode = char.charCodeAt(0)
return charCode >= 0 && charCode <= 128
}
/**
* 合并处理
* @param data 原始数组
* @param mergeColNames 必填 [需要合并的列,默认合并列相同的数据]
* @param firstMergeColNames 可选 [受影响的列,只合并以firstMerge为首的同类型数据]
* @param firstMerge 可选 [以哪列为基础进行合并,一般为第一列]
* @param property 按照xx属性排序
* @returns {*}
*/
export function cellTableMerge(data, mergeColNames, firstMergeColNames, firstMerge, property, order) {
return mergeTableRow({
// 给table赋值,重新遍历新增rowSpan属性,checkRoom,appointmentTime为table里面需要合并的属性名称
data: sortArray(data, property, order),
mergeColNames,
firstMergeColNames,
firstMerge
})
}
完结,记录下遇到的表格处理。例外,一些参考文献:
vxe-table:处理复杂的表格,一般满足业务中的场景。