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

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

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

展示的效果:

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

相关推荐
weixin_382395231 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__1 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.2 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~3 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华3 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子6 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅6 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni6 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学7 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端