写了两个小需求,终于搞清楚了表格合并

最近做了两个关于表格合并的两个小需求,正好借此机会把行和列的合并来总结一下。

演示代码的技术栈:vben-admin、ant-design-vue

最基础的行合并

rowSpan是行合并属性,例如第一行和第二行合并,我们就这样写:

js 复制代码
 customCell: (_, index) => {
  if(index == 0) {
    return { rowSpan: 2 }; // 表示从index=0开始跨两行
  } else if(index == 1) {
    return { rowSpan: 0 } // 上面那一行跨了两行,所以这一行无需展示了
  } else {
    return { rowSpan: 1 } // 不做处理的行
  }
}

带复杂逻辑的行合并

效果图一:按数字递增进行行合并

需求:一个蛋糕最多N个人分,需要设置两个人分按什么比例,三个人分按什么比例,N个人分按什么比例。

转化成页面,就是一个金字塔形的表格,第一行是100%,二三两行合并,然后后面四行合并

这里主要的逻辑点在于寻找行的索引与rowSpan之间的关系:

索引 rowSpan
0 1
1 2
2 0
3 3
4 0
5 0
6 4
7 0
8 0
9 0

这种场景下,我们只需要把开始合并的那一列记录下来,其余的都是0,得到这样的数据:

合并起始位置 合并几列
0 1
1 2
3 3
6 4
10 5

得到公式:(n-1)n/2

需要合并n行的时候,我们从第几行开始合并呢?

起始行的索引就是把已经合并过的行进行累加:

js 复制代码
/*
const sum = (maxVal) => {
  if(maxVal == 0) {
    return 0
  } else {
    return sum(maxVal - 1) + maxVal
  }
}
*/
// 尾递归的优化
const sum = (maxVal, result) => {
  if(maxVal == 0) {
    return result
  } else {
    return sum(maxVal - 1, result + maxVal)
  }
}
customCell: (_, index) => {
  let maxNum = _.maxNum // 人数最大值
  if(index == sum(maxNum - 1, 0)) {
	return { rowSpan: maxNum };
  } else {
	return { rowSpan: 0 } 
  }
},
// 用数学知识直接算好,也就是等差数列求和公式:
customCell: (_, index) => {
  let maxNum = _.maxNum // 人数最大值
  if(index == (maxNum - 1 * maxNum)/2) {
	return { rowSpan: maxNum };
  } else {
	return { rowSpan: 0 } 
  }
},

展示的效果:

合并列(进阶)

效果图二:相邻相同的列数据进行合并

90, 100, 100, 99, 100, 100, 100, 99, 99, 90

对应的colSpan值是: 1, 2, 0, 1, 3, 0, 0, 2, 0, 1

其实就三种状态:列合并起始数字、被合并列(0),无需合并的列(1)

js 复制代码
function getColSpan(colums, dataObj) {
  let arr = colums.map(v => {
    return {
      key: v.dataIndex,
      value: dataObj[v.dataIndex]
    }
  })
  var merged = arr.map((val, i) => {
    // 与前后都不相等,就返回1
    // 与前面一位相等,就返回0
    // 与后面一位相等,就继续往后找,返回找到的长度
    let v = val.value
    let prev
    let next
    if (i != 0) {
      prev = arr[i - 1].value
    }
    if (i != arr.length - 1) {
      next = arr[i + 1].value
    }
    if (v != prev && v != next) {
      return {
        colSpan: 1
      }
    } else if (v == prev) {
      return {
        colSpan: 0
      }
    } else {
      let temp = v
      let j = i
      while (v == temp) {
        j = j + 1
        temp = arr[j].value // 超出就是null了
      }
      return {
        colSpan: j - i
      }
    }
  })
  return merged
}

核心逻辑就在于上面这个方法,处理了所有的场景,每个单元格都赋值了一个colSpan的值。

展示的效果:

总结:代码只是工具,分析问题才是核心。

相关推荐
Amos_Web31 分钟前
Markdonw语法
开发语言·前端·javascript
小万74232 分钟前
刚发布就冲上GitHub热榜!Filee支持244种格式转换,完全免费还全本机运行
前端
星光不问赶路人33 分钟前
Vue 3 对象监听与快照:ref 和 reactive 的关键差异
前端·vue.js
世界一刘先生34 分钟前
不引入 JSZip,自己写一个 ZIP 打包器:CRC32、中央目录与 UTF-8 文件名
前端
全栈项目管理程序猿34 分钟前
ArcGIS JS 基础教程(34):体元系列 - 等值面 VoxelIsosurface
前端·javascript
代码搬运媛36 分钟前
如何使用 @codemirror/view 库创建一个简单的代码编辑器
前端
huali38 分钟前
草稿该存在哪:per-session 是怎么成为共识的
前端·产品经理·产品
IPIPD40 分钟前
Proxifier规则为什么没有生效?从连接日志定位规则命中与DNS路径
前端
baiyunfan41 分钟前
微信小程序做 PDA 扫码出入库:库存并发控制与 4 个坑
前端