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

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

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

展示的效果:

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

相关推荐
coding随想1 小时前
JavaScript ES6 解构:优雅提取数据的艺术
前端·javascript·es6
小小小小宇1 小时前
一个小小的柯里化函数
前端
灵感__idea1 小时前
JavaScript高级程序设计(第5版):无处不在的集合
前端·javascript·程序员
小小小小宇2 小时前
前端双Token机制无感刷新
前端
小小小小宇2 小时前
重提React闭包陷阱
前端
小小小小宇2 小时前
前端XSS和CSRF以及CSP
前端
UFIT2 小时前
NoSQL之redis哨兵
java·前端·算法
超级土豆粉2 小时前
CSS3 的特性
前端·css·css3
星辰引路-Lefan2 小时前
深入理解React Hooks的原理与实践
前端·javascript·react.js
wyn200011282 小时前
JavaWeb的一些基础技术
前端