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

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

演示代码的技术栈: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的值。

展示的效果:

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

相关推荐
JeffongTan8 小时前
在LWC中镶嵌VF Page获取用户IP
前端·javascript·salesforce
陆枫Larry10 小时前
Astro 是什么
前端
是立不是利12 小时前
写给设计师的 CSS 博客美学指南
前端·css
默_笙12 小时前
🏝 Docker 就是"房地产开发":从施工图纸到小区物业的容器化指南
前端·javascript
计算机魔术师12 小时前
Rohan Paul 谈用时间跨度衡量智能体能力,并引用 OpenAI 自动化研究实习生里程碑
前端
kyriewen12 小时前
我手写了个极简版 React Router——才搞懂 v6 为什么砍了这么多 API
前端·javascript·程序员
a11177613 小时前
Shirone 二次元博客主题 开源
前端·开源
IT_陈寒13 小时前
Python的切片赋值把我坑惨了,这不是bug是特性
前端·人工智能·后端
掘金酱13 小时前
【社区公告】致每一位掘友:关于这次调整, 想再说几句
前端·人工智能
CoderLiu13 小时前
程序化工具调用(PTC)与动态工作流引擎:深入大模型工具调用的架构演进与实践
前端·人工智能·后端