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

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

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

展示的效果:

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

相关推荐
键盘不能没有CV键1 小时前
【图片处理】✈️HTML转图片字体异常处理
前端·javascript·html
yantuguiguziPGJ1 小时前
WPF 联合 Web 开发调试流程梳理(基于 Microsoft.Web.WebView2)
前端·microsoft·wpf
大飞记Python2 小时前
部门管理|“编辑部门”功能实现(Django5零基础Web平台)
前端·数据库·python·django
tsumikistep3 小时前
【前端】前端运行环境的结构
前端
你的人类朋友3 小时前
【Node】认识multer库
前端·javascript·后端
Aitter3 小时前
PDF和Word文件转换为Markdown的技术实现
前端·ai编程
mapbar_front3 小时前
面试问题—上家公司的离职原因
前端·面试
昔人'4 小时前
css使用 :where() 来简化大型 CSS 选择器列表
前端·css
昔人'4 小时前
css `dorp-shadow`
前端·css
流***陌4 小时前
扭蛋机 Roll 福利房小程序前端功能设计:融合趣味互动与福利适配
前端·小程序