保姆级教程 | 表格自动行合并实现
在 element-ui 和 antv 中都有表格合并,但如何确定哪几行要合并呢? 在随机给定数据的情况下,如何实现自动合并呢?本文将一一解答这些问题。
并在延伸中,谈到了,如何将本文的方法应用到element-ui和antv中。
一、需求描述及样例展示
① 自动行合并
② 当两列为层级关系的时候,合并要有层级关系。
在举例之前,我们先规定一下展示数据。
展示的是不同 app 在不同手机型号下的下载量。
数据为:
// 行信息
const columns = [{key:'app',label:'app',},{key:'phone',label:'手机类型',},{key:'phoneType',label:'手机型号',},{key:'downloadCount',label:'下载量',},
];//数据信息
const data = [{app:'微信',phone:'iphone',phoneType:'iphone11',downloadCount:'138,999,999'},{app:'微信',phone:'iphone',phoneType:'iphone12',downloadCount:'138,999,999'},{app:'微信',phone:'huawei',phoneType:'mate40',downloadCount:'138,999,999'},{app:'微信',phone:'huawei',phoneType:'mate40pro',downloadCount:'138,999,999'},{app:'抖音',phone:'huawei',phoneType:'mate40',downloadCount:'138,999,999'},{app:'抖音',phone:'iphone',phoneType:'iphone12',downloadCount:'138,999,999'},{app:'抖音',phone:'iphone',phoneType:'iphone11',downloadCount:'138,999,999'},
]
常规表格展现结果为:
APP | 手机类型 | 手机型号 | 下载量 |
---|---|---|---|
微信 | iphone | iphone11 | 138,999,999 |
微信 | iphone | iphone12 | 138,999,999 |
微信 | huawei | mate40 | 138,999,999 |
微信 | huawei | mate40pro | 138,999,999 |
抖音 | huawei | mate40 | 138,999,999 |
抖音 | iphone | iphone12 | 138,999,999 |
抖音 | iphone | iphone11 |
138,999,999 |
产品最终要的结果是:
这里要注意的是:
虽然手机类型都是华为,但如果是不同 app,也不能合并。
虽然手机型号都是 mate40 pro,也要依据 app 是否相同才能进行合并。
二、需求剖析
2.1 合并功能原生实现
这里我们以原生html实现这种合并功能。
先来看看,html 实现表格的行合并的方式,代码如下。
<table border="1">
<tr><th>First Name</th><th>Bill Gates</td>
</tr>
<tr><td rowspan="2">Telephone:</th><td>555 77 854</td>
</tr>
<tr><td style="display:none;">Telephone:</th><td>555 77 855</td>
</tr>
</table>
效果图如下:
可以得知,原生html 是通过 在列上设置 rowspan 来实现行合并。rowspan 的 数值为几则合并几行。
2.2 vue 实现表格渲染
但在实际需求中,表格的渲染一定是批量完成的。
以上述手机下载量数据为例,在vue中,渲染这个表格的代码为:
<table><tr><td v-for="column in columns"> {{column.label}}</td></tr><tr v-for="(item, index) in data"><td v-for="column in columns">{{item[column.key]}}</td></tr></table>
2.3 vue 实现表格行合并渲染
由上述信息可知,为了实现行合并,我们需要知道,每一列数据中,
①开始合并的行,在开始合并的行添加 rowspan 和 数值
②结束合并的行,在开始合并行和结束合并行之间的所有行style 添加 display :none。
将上述三个需要计算的数值可以抽象为:
/** 合并行 */
interface MergeRow {/** 开始合并的行 */start: number;/** 开始合并的行 */end: number;/** 一共合并的行数: end - start + 1 */count: number;
}
2.3.1 计算行合并
计算以上三个数值,可以抽象为: 在数组中,找到连续重复的数。
这是一个很简单的OJ问题,需要一个变量记录个数即可。 那么,把这个问题稍稍扩展一下,变成,找到数组中有几组连续重复的数,并记录开始重复,结束重复和重复数量。
那么解法就变成了如下代码:
const {data, columns} = table;const newColumns = columns.map((column)=>{/** 当前列的key */ const valKey = column.key;/** 当前列中需要 行合并的信息 */ const merge:MergeRow[] = [];//第一行数据let lastVal = data[0][valKey];let valNum = 0;let startIndex = 0;data.forEach((item,index)=>{/** 当前行,当前列对应的数值 */const curValue = item[valKey];// 当前值和上一行的值相等,则计数+1if(curValue === lastVal) {valNum ++;}// 如果当前值和上一行的值不相等,并且计数大于1的话,则上几行存在相邻相等的数值,需要记录if(curValue !== lastVal) {merge.push({start:startIndex,end: index - 1,count: valNum,});// 如果当前值和上一行的值不相等,并且计数小于等于1. 则上一行没有数据需要记录,进行覆盖lastVal = curValue;valNum = 1;startIndex = index;} if(index === data.length -1) {merge.push({start:startIndex,end: index - 1,count: valNum,});}});column.merge = merge;return column;});
注意,在在上面的代码中,我把每一列中,存在的合并信息,存到了merge属性中。
这是为了渲染的时候可以读取这些信息准备的。
2.3.2 vue 渲染行合并
渲染的代码如下:
<table><tr><td v-for="column in columns"> {{column.label}}</td></tr><tr v-for="(item,index) in data"><td v-for="column in columns"display="display:`${colum.merge ? colum.merge.find(m=>m.start == index) ? 'auto':'none':'auto'}`"rowspan="`${colum.merge && colum.merge.find(m=>m.start == index) ? colum.merge.find(m=>m.start == index).count : 1}`">{{item[column.key]}}</td></tr></table>
主要是添加了display 和 rowspan的逻辑。
display这里使用了两次三元运算符,
第一次,判断当前列的数据中是否存在merge ,如果不存在merge,则当前行正常渲染;
第二次,当存在merge的时候,判断是否是开始合并行,如果是,则正常渲染,不是则隐藏当前面行。
rowspan 只使用了一次三元判断,判断是否是开始合并行,如果是则读取count, 不是则为1.
2.3.3 级联渲染
看似我们已经实现了自动行合并,但,实际还有一个问题,上述方法,每一列的行合并是独立的。
再看这个图,手机类型这一列,有三行都是huawei,但是,不隶属于同一个app,所以不能合并。
为了解决这个问题,我们需要在计算合并的时候,打一个补丁:
判断一下,当这两行相等的时候,上一列的这两行是否也相等。
友情提示: 可看补丁部分。
const newColumns = columns.map((column,colIndex)=>{/** 当前列的key */ const valKey = column.key;// 补丁:上一列的 keyconst prevColKey = colIndex -1 >= 0 ? columns[colIndex - 1].key : valKey;/** 当前列中需要 行合并的信息 */ const merge:MergeRow[] = [];let lastVal = data[0][valKey];// 补丁:上一列当前行的值let lastPrevColVal = data[0][prevColKey];let valNum = 0;let startIndex = 0;data.forEach((item,index)=>{/** 当前行,当前列对应的数值 */const curValue = item[valKey];const curPrevColValue = item[prevColKey];// 当前值和上一行的值相等,则计数+1if(curValue === lastVal) {// 补丁: 判断上一列是否相等if(lastPrevColVal === curPrevColValue) {valNum ++;} else {merge.push({start:startIndex,end: index - 1,count: valNum,});// 如果当前值和上一行的值不相等,并且计数小于等于1. 则上一行没有数据需要记录,进行覆盖lastVal = curValue;// 这里也要重新赋值lastPrevColVal = curPrevColValue;valNum = 1;startIndex = index;}}// console.log('this is index', curValue, lastVal, valNum);// 如果当前值和上一行的值不相等,并且计数大于1的话,则上几行存在相邻相等的数值,需要记录if(curValue !== lastVal) {merge.push({start:startIndex,end: index - 1,count: valNum,});// 如果当前值和上一行的值不相等,并且计数小于等于1. 则上一行没有数据需要记录,进行覆盖lastVal = curValue;// 这里也要重新赋值lastPrevColVal = curPrevColValue;valNum = 1;startIndex = index;} if(index === data.length -1) {merge.push({start:startIndex,end: index - 1,count: valNum,});}});merge.length && (column.merge = merge);return column;});
三、总结
到此为止,也就实现了表格的自动级联行合并。
其实预计这是一篇很短就可以说清楚的问题。但没想到写了整整半天。
在写的过程中,遇到的第一个问题是:如何把问题界定清楚?
也就是文章的第一部分。 为什么这么难?因为在跟产品讨论时,不需要上下文,天然我们明白彼此的问题。但读者并不清楚需求上下文的,所以我需要站到一个产品的角度去描述这个需求的边界。
第二个问题是,如何告诉阐述思考的过程?
这也是一定要写这篇文章的原因,在工作的这一年里,我第一次把学生时代的内容进行了实战,发现了很多落地的实践。 但在现在的技术博客和当今的大学计算机教学中,都极少见到类似文章。所以,就想通过本文展示如何将具象问题抽象成一个教科书问题。
即是希望给看到这篇文章的学生们一点工程视野,也想听听各位大佬的看法,看我思考问题是否有所偏差,这个问题有没有更好的解决方法。
那么,针对这个问题,我最终确定了如下思路:
① 用demo 界定问题。
② 放置前置知识(table 行合并 和vue 渲染表格)
③ 拆解行合并问题,并进一步抽象细化成数组重复问题。
④ 解决数组重复问题
⑤ 向上包装,解决行合并。
⑥ 向上包装,解决级联行合并。
⑦ 实现 vue 渲染。
这个过程可以说是一个经典的洋葱式思考,层层抽丝剥茧,找到问题的根源。 然后,再一层层往上包装。
私以为,这种解决问题的方式和算法中的分治法异曲同工,其精髓都是问题细化,逐步击破。
四、延伸
这一部分稍稍谈一下,如何把计算得到的合并参数应用到element-ui中。
通过给
table
传入span-method
方法可以实现合并行或列,方法的参数是一个对象,里面包含当前行row
、当前列column
、当前行号rowIndex
、当前列号columnIndex
四个属性。该函数可以返回一个包含两个元素的数组,第一个元素代表rowspan
,第二个元素代表colspan
。 也可以返回一个键名为rowspan
和colspan
的对象。引用自element-ui官网:Element - The world's most popular Vue UI framework
实际上,2.3.3 的代码中,item 就是当前行,column就是当前列。
剩下的,相信你一定可以!
那,为什么,我没有直接从element-ui的这个方法开始讲述呢?
因为我的实际是服务端渲染,用的模板语言,只能用原生htm了,呜呜呜。
五、参考资料
剑指Offer面试题03-找出数组中重复的数字(5种方法)_JohnArchie的博客-CSDN博客_剑指offer 寻找重复数
分治法_百度百科
保姆级教程 | 表格自动行合并实现相关推荐
- 量化交易-利用同花顺量化平台supermind 5行代码搞定多条件选股并微信实时收消息-保姆级教程
利用supermind 5行代码搞定多条件选股并在微信实时收消息-保姆级教程 前言 对大部分炒股的朋友来说,日常最耗时的就是盯着选股条件然后不停的选股,我经常苦恼于有无程序能自动化实现选股,然后选中之 ...
- github博客自动同步到gitee(保姆级教程)
github博客自动同步到gitee(保姆级教程) 前言: 由于国内网访问github实在太慢!虽然在公司可以连接外网访问还算可以,但是回学校想看看博客或者分享给别人的时候经常会崩掉!于是我想可不可以 ...
- Unity教程2:保姆级教程.几行代码实现输入控制2D人物的移动
目录 人物的创建以及刚体的设置 图层渲染层级设置 角色碰撞箱设置 使用代码控制人物移动 创建脚本文件 初始函数解释 控制移动代码 初始化变量 获得键盘输入 调用函数 手册链接在这:Unity User ...
- Tkinter保姆级教程(下)
继上次肝了几天的Tkinter保姆级教程(上),接下来继续肝教程下,冲冲冲. 目录 Scale控件 Canvas画布控件 Menu菜单控件 Scrollbar滚动条控件 Event事件处理 布局管理器 ...
- 图片适应窗口_毕业论文排版保姆级教程——图片和公式排版
[小技巧]Origin作图过程中如何让图看起来更生动 2020-05-30 [小技巧]简单设置让你origin导出的图片不在有大白边 2020-05-29 [干货放送]萤火科研资源免费赠送第一期--必 ...
- 保姆级教程 CSS 知识点梳理大全,超详细!!!
保姆级教程 CSS 知识点梳理大全,超详细!!! ✴️大家好,我是王同学,好久不见,趁着假期王同学把CSS 知识点梳理了一遍 ✴️如果对你有帮助就给我点个赞吧,这样我们就互不相欠了 ✴️星光不负赶路人 ...
- 前端学习笔记 HTML5 保姆级教程
HTML5 保姆级教程 前端学习路线: HTML→CSS→JavaScript→jQuery→HTML5→CSS3→ES6→Vue.js→webpack→Node.js 除了掌握这些技术,后期我还需要 ...
- 50000字,数仓建设保姆级教程,离线和实时一网打尽(理论+实战) 下
文档大纲: 本文上半部分之前已经发过了,传送门:50000字,数仓建设保姆级教程,离线和实时一网打尽(理论+实战) 上 此篇文章是整个文档的下半部分,将接着上半部分从第五章开始. 五.实时数仓建设核心 ...
- 金融数据获取:当爬虫遇上要鼠标滚轮滚动才会刷新数据的网页(保姆级教程)
目录 1. 谁这么会给我整活儿 2. Selenium模拟网页浏览器爬取 2.1 安装和准备工作 2.2.1 高度判断 2.2.2 顶部距离判断 3: 爬取内容 4: 完整代码,结果展示 1. 谁这么 ...
最新文章
- mysql select语句详解_mysql学习笔记之完整的select语句用法实例详解
- 2020.12.07.记录
- Google protobuf解析消息逻辑的版本问题
- redis中的zset
- 调用函数,计算分段函数的值
- (36) css企业代码书写规范
- 非标自动化企业前十名_自动化输送+旋盖,竟如此简单!机械设计教程精选!...
- 【优化算法】爬虫搜索算法(RSA)【含Matlab源码 1838期】
- JS中 post和get的区别
- php 万能密码,万能用户名和万能密码
- 聚簇索引,非聚簇索引
- 数字图像处理——灰度级、动态范围、对比度
- css3 transition属性造成文字抖动
- Xshell、Xftp软件评估过期解决方案
- Linux:生成core的几种方式
- python 爬虫爬取无损图片 批量下载wallhaven超清壁纸
- 搜索优化—如何在Google搜索引擎上排名靠前Google左侧排名
- 【游戏开发】unity教程4 打飞碟小游戏
- 老旧车标致206能卖多少钱?且看团车网老旧车置换拍卖体验
- 6个习惯让你立刻远离拖延
热门文章
- 大津法Python实现
- 刚柔软机器人参数化建模仿真分析--多种案例操作步骤--案例代码分享
- Dockerfile、Docker-Compose
- struts的勤工俭学系统(带文档和演示)
- ls: 读取目录 .: 输入/输出错误 错误处理
- 掌握这些电子书搜索技巧与工具,拥有读不尽的书,从此不再闹书荒
- 牛津大学团队采用先进机器人技术,推动「人造肌腱」实际应用
- 利用python爬取豆瓣音乐_python爬虫之豆瓣音乐top250
- Python轻量级爬虫教程-网页下载器
- 家用台式计算机硬件配置清单,最新最全台式电脑配置清单2000-5000配置清单