表格实现合并单元格

实现的效果

在这里插入图片描述

一、列合并

此需求的列合并比较简单, 直接使用el-table-column包括即可

<el-table-column align="center" sortable label="目标"><el-table-column prop="target1" sortable label="预设目标" /><el-table-column prop="target1" sortable label="目标值" />
</el-table-column>

二、行合并

1. 排序

1)原因

因为哪些单元格需要合并,哪些单元格就必须挨着,不挨着就无法进行单元格合并

2)实现思路

1、使用sort
2、由于大多数场景判断的字段都是字符串格式,不能直接使用a-b的形式来判断,所以使用判断大小来代替;
3、由于可能存在多个判断条件,比如按照学校和专业排序,学校相同的还需要按专业排序;
4、排序规则

  • 如果a.xx < b.xx,则返回-1,代表升序;
  • 如果a.xx > b.xx,则返回1,代表降序;
  • 如果相等,则需要判断是否还有其他判断条件,如果没有,则返回0,代表不做处理;如果有,则执行递归,继续以其他判断条件按照以上两个步骤进行判断大小;

3)代码实现

/*** 按一系列参数排序* @param {*} table 原数组* @param {*} names 排序的列的数组*/
getSortArr(table, names) {return table.sort((a, b) => {function sortFn(names, index) {const itemA = a[names[index]]const itemB = b[names[index]]if (itemA < itemB) {return -1;} else if (itemA > itemB) {return 1;} else {// 如果当前列的值相同// 如果最大列索引值还大于当前列索引,则递归, 判断下一列的值,否则返回0即可if (names.length - 1 > index) {return sortFn(names, index + 1);} else {return 0;}}}return sortFn(names, 0)});
},

2. 生成单元格数据

1)原因

因为每一个单元格是否需要合并、是否需要被合并,以及需要合并的话要合并多个单元格,需要用一个固定的数据来控制

2)实现思路?

1、遍历排序之后的数据,判断该项是否与前一项的条件相等(第一项无需判断)
2、判断条件是有层级的,比如需要判断学校和专业,如果当前是在判断学校是否相等,那么就不需要考虑专业的情况;但如果当前是在判断专业,那么必须保证两者学校也是同一个,否则不能作合并处理;
3、定义一个数组,用于存储各个单元格的值;当不需要作合并处理时,存储一个和所在列索引值一致的数据即可,当需要作合并处理时,存储一个大于所在列索引值的数据,当需要被合并(即该单元格不会显示)时,存储0;

  • 举例:存储数据为[0,1,3,0,4],
    - 索引为0,1,4的单元格,存储值和索引一致,代表不需要合并
    - 索引为2的单元格,存储值为3,代表需要合并到索引为3的单元格
    - 索引为3的单元格,存储值为0,代表需要被合并,该单元格不需要显示

3)代码实现

/*** 生成各单元格的数据* @param {*} tableData 原数据* @param {*} rowSpanType 判断条件列的数组*/
handleTableData(tableData, rowSpanType) {const result = {}; // 存储数据// 由于是多个判断条件,所以需要遍历for (var i = 0; i < rowSpanType.length; i++) {const rowSpanArr = []; // 存储数据let position = 0; // 存储数据的索引值// 遍历原数据的每一项,与前一项对比tableData.forEach((item, index) => {// 第一项直接存储,不作处理if (index == 0) {rowSpanArr.push(0);position = 0;} else {// 判断与前一项的值是否相等(包括此列之前所有的列的值)function isEqual() {for (var j = i; j >= 0; j--) {if (item[rowSpanType[j]] == tableData[index - 1][rowSpanType[j]]) {continue;} else {return false;}}return true;}if (isEqual()) {rowSpanArr[position] += 1; // 前一项需要合并,存储值+1,代表需要合并到哪一行rowSpanArr.push(0); // 该项需要被合并,存储值为0,} else {// 与索引相等,代表不需要合并rowSpanArr.push(index);position = index;}}});result[rowSpanType[i]] = rowSpanArr;}return result;
},

3. 合并

思路分析

el-table提供了合并行或列的计算方法,即span-method,直接使用即可
参数: row当前行,column当前列的数据、rowIndex当前行索引、columnIndex当前列索引
返回值(可返回数组或对象)
- 没有处理,代表不需要合并,也不需要被合并
- 返回1,代表不作合并处理
- 返回0,代表被合并
- 返回值大于1,代表会合并到多少单元格
- 举例:当columnIndex=0, rowIndex=0时,return [2,1]或者{rowspan:2,colspan:1},代表第一行第一列合并了第二行第一列

难点

但是什么条件下返回,返回什么值是个问题,所以每个单元格都需要一个数据来控制自己是否需要合并,是否需要被合并,以及如果合并需要合并多少格,通过思路2我们已经实现。

代码实现

spanMethod({ row, column, rowIndex, columnIndex }) {// 由于是多个判断条件,多个列都需要合并,所以需要遍历for (var i = 0; i < this.rowSpanType.length; i++) {// 作某一列的合并处理if (column.property === this.rowSpanType[i]) {// 拿到当前单元格的存储数据const rowspan = this.rowSpanArr[this.rowSpanType[i]][rowIndex];// rowspan == rowIndex 代表不需要合并单元格,此处只需处理需要合并、需要被合并的单元格if (rowspan != rowIndex) {// rowspan===0代表被合并,!=0代表合并的目标行数if (rowspan === 0) {// 被合并的单元格,返回0即可return { rowspan: 0 };// return [0, 1]} else {// 合并数 = rowspan合并到的行数 - 当前所在的行数 + 1return { rowspan: rowspan - rowIndex + 1, colspan: 1 };// return [rowspan - rowIndex + 1, 1]}}}}
},

三、整体代码实现

使用的话,直接更改data中两个值即可,其他地方不需要动。

  • tableData 改成你的表格数据
  • rowSpanType 存放你需要合并的列(有顺序)
<template><div><el-table :data="tableData" :span-method="spanMethod" border style="width: 100%"><el-table-column prop="company" label="公司" /><el-table-column prop="division" label="部门" /><el-table-column prop="type" label="类别" /><el-table-column prop="name" label="项目" /><el-table-column align="center" sortable label="指标"><el-table-column prop="amount1" sortable label="指标1" /><el-table-column prop="amount2" sortable label="指标2" /></el-table-column><el-table-column align="center" sortable label="目标"><el-table-column prop="target1" sortable label="预设目标" /><el-table-column prop="target1" sortable label="目标值" /></el-table-column></el-table></div>
</template><script>
export default {data() {return {tableData: [],// 单元格的数据rowSpanArr: {},// 需要排序和合并的列。按顺序// 此处代表先按公司排序,公司相同的按部分排序,再相同的按类型排序,以此类推rowSpanType: ['company', 'division', 'type'],};},created() {this.tableData = this.initTableData(10);this.tableData = this.getSortArr(this.tableData, this.rowSpanType);this.rowSpanArr = this.handleTableData(this.tableData, this.rowSpanType);},methods: {/*** 生成模拟表格数据* @param {*} num 数据数量(行数)*/initTableData(num) {const result = []// 生成随机数据for (var i = 0; i <= num; i++) {const company = ['A', 'B', 'C'][this.getRandomInt(0, 2)];const division = ['x', 'y', 'z'][this.getRandomInt(0, 2)];const type = ['a', 'b', 'c', 'd', 'e', 'f'][this.getRandomInt(0, 5)];const name = this.getRandomInt(1, 4);result.push({id: i,company: `公司${company}`,division: `部门${division}`,type: `类别${type}`,name: `${company}、${division}、${type}`,amount1: `${this.getRandomInt(100, 1000)}`,amount2: `${this.getRandomInt(100, 1000)}`,target1: `${this.getRandomInt(100, 1000)}`,target2: `${this.getRandomInt(100, 1000)}`,});}return result;},/*** 按一系列参数排序* @param {*} table 原数组* @param {*} names 排序的列的数组*/getSortArr(table, names) {return table.sort((a, b) => {function sortFn(names, index) {const itemA = a[names[index]]const itemB = b[names[index]]if (itemA < itemB) {return -1;} else if (itemA > itemB) {return 1;} else {// 如果当前列的值相同// 如果最大列索引值还大于当前列索引,则递归, 判断下一列的值,否则返回0即可if (names.length - 1 > index) {return sortFn(names, index + 1);} else {return 0;}}}return sortFn(names, 0)});},/*** 生成随机数* @param {*} min  最小值* @param {*} max  最大值*/getRandomInt(min, max) {return min + parseInt(Math.random() * (max - min + 1));},spanMethod({ row, column, rowIndex, columnIndex }) {for (var i = 0; i < this.rowSpanType.length; i++) {if (column.property === this.rowSpanType[i]) {const rowspan = this.rowSpanArr[this.rowSpanType[i]][rowIndex];// rowspan == rowIndex 代表不需要合并单元格,不作处理,在此只处理需要合并的if (rowspan != rowIndex) {// rowspan===0代表被合并,!=0代表合并的目标行数if (rowspan === 0) {// 被合并的域return { rowspan: 0 };} else {// rowspan合并到的行数 - 当前所在的行数 + 1 = 合并数return { rowspan: rowspan - rowIndex + 1, colspan: 1 };}}}}},/*** 生成各行的合并数据* @param {*} tableData 原数据* @param {*} rowSpanType 需要合并的列的数组*/handleTableData(tableData, rowSpanType) {const result = {};for (var i = 0; i < rowSpanType.length; i++) {const rowSpanArr = [];let position = 0; // 当前索引tableData.forEach((item, index) => {if (index == 0) {rowSpanArr.push(0);position = 0;} else {// 判断与前一项的值是否相等(包括此列之前所有的列的值)function isEqual() {for (var j = i; j >= 0; j--) {if (item[rowSpanType[j]] == tableData[index - 1][rowSpanType[j]]) {continue;} else {return false;}}return true;}if (isEqual()) {// 代表需要合并到哪一行rowSpanArr[position] += 1;rowSpanArr.push(0);} else {// 与索引相等,代表不需要合并rowSpanArr.push(index);position = index;}}});result[rowSpanType[i]] = rowSpanArr;}return result;},},
};
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/238742.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在Linux下搭建接口自动化测试平台

我们今天来学习一下在Linux下如何搭建基于HttpRunner开发的接口自动化测试平台吧&#xff01; 需要在Linux上提前准备的环境&#xff08;下面是本人搭建时的环境&#xff09;&#xff1a; 1&#xff0c;Python 3.6.8 2&#xff0c;MySQL 5.7 一&#xff1a;下载HttpRunner…

JMeter---JSON提取器

JMeter的JSON提取器是一个用于从JSON响应中提取数据的元件。它可以从JSON响应中提取特定字段的值&#xff0c;并将这些值用于后续的测试步骤。 使用JSON提取器的步骤如下&#xff1a; 添加一个HTTP请求&#xff0c;用于获取包含JSON响应的数据。 在HTTP请求之后添加一个JSON提…

JavaScript高级 构造函数与原型篇

构造函数与原型 1、构造函数 构造函数是一种特殊的函数&#xff0c;主要用来初始化对象&#xff0c;即为对象成员变量赋初始值&#xff0c;它总与new一起使用。我们可以把对象中一些公共的属性和方法抽取出来&#xff0c;然后封装到这个函数里面。 // 定义学生构造函数func…

面试遇到了接口分析和测试用例分析题,该如何下手?

只要有软件产品的公司百分之九十以上都会做接口测试&#xff0c;要做接口测试的公司那是少不了接口测试工程师的&#xff0c;接口测试工程师相对于其他的职位又比较轻松并且容易胜任。如果你想从事接口测试的工作那就少不了对接口进行分析&#xff0c;同时也会对测试用例进行研…

软件测试十大必问面试题(附答案和解析)

01 介绍之前负责的项目 参考答案&#xff1a;先大概描述一下这个项目是做什么的&#xff08;主要功能&#xff09;&#xff0c;包括哪些模块&#xff0c;是什么架构的&#xff08;B/S、C/S、移动端&#xff1f;&#xff09;&#xff0c;你在其中负责哪些模块的测试。期间经历了…

【排序算法】C语言实现选择排序与冒泡排序

文章目录 &#x1f680;前言&#x1f680;冒泡排序✈️冒泡排序的逻辑✈️冒泡排序coding &#x1f680;选择排序✈️选择排序的逻辑✈️选择排序coding &#x1f680;前言 这里是阿辉算法与数据结构专栏的第一篇文章&#xff0c;咱们就从排序算法开始讲起&#xff0c;排序算法…

金蝶Apusic应用服务器 loadTree JNDI注入漏洞复现(QVD-2023-48297)

0x01 产品简介 金蝶Apusic应用服务器是一款企业级应用服务器,支持Java EE技术,适用于各种商业环境。 0x02 漏洞概述 由于金蝶Apusic应用服务器权限验证不当,导致攻击者可以向loadTree接口执行JNDI注入,造成远程代码执行漏洞。利用该漏洞需低版本JDK。(漏洞比较旧,8月份…

测试框架|Burp Suite几个基本工具的使用

前阵子项目上想通过测试工具在网页上模拟返回错误代码 500 来查看页面的错误处理&#xff0c;然后去调查了下 burp suite&#xff0c;看了些基本工具的使用文档。虽然最后证实 burp suite 只能用来处理页面测试应用程序的实际行为和响应&#xff0c;而不是尝试模拟不存在的问题…

springboot学习笔记(五)

MybatisPlus进阶 1.MybatisPlus一对多查询 2.分页查询 1.MybatisPlus一对多查询 场景&#xff1a;我有一个表&#xff0c;里面填写的是用户的个人信息&#xff08;姓名&#xff0c;生日&#xff0c;密码&#xff0c;用户ID&#xff09;。我还有一个表填写的订单信息&#x…

4 postman响应数据解析

上一篇:3 使用postman批量创建测试数据-CSDN博客 在接口测试中,从接口的响应结果中获取数据是很常用的。比如说做断言的时候,需要确保接口返回数据是符合预期的。又比如有些接口的输入参数值,需要用到前面接口运行返回的数据。下面先介绍如何解析响应数据(以json数…

持续集成交付CICD:GitLabCI 封装Python类 并结合 ArgoCD 完成前端项目应用发布

目录 一、实验 1. 环境 2. Python代码实现获取文件 3.Python代码实现创建文件 4.Python代码实现更新文件 5.GitLab更新库文件与运行流水线 6.ArgoCD 完成前端项目应用发布 二、问题 1.Python获取GitLab指定仓库文件报错 2. K8S master节点运行Python代码报错 一、实验…

Java日志框架Logback

logback.xml文件配置(放在src下微服务建议放在resources下) <?xml version"1.0" encoding"UTF-8"?> <configuration><!--定义日志文件的存储地址,使用绝对路径--><property name"LOG_HOME" value"d:/logs"/>…

文件上传——后端

文件上传流程&#xff1a; 创建阿里云OSS&#xff08;对象存储服务&#xff09;的bucket 登录阿里云&#xff0c;并完成实名认证&#xff0c;地址&#xff1a;https://www.aliyun.com/. 可以通过搜索&#xff0c;进入以下页面&#xff1a; 点击立即使用后&#xff1a; 点击…

Goby 漏洞发布| 金蝶 EAS createDataSource 路径 jndiName 参数远程代码执行漏洞

漏洞名称&#xff1a;Apusic 应用服务器 createDataSource 远程代码执行漏洞 English Name&#xff1a;Kingdee EAS createDataSource path jndiName parameter remote code execution vulnerability CVSS core: 9.8 影响资产数&#xff1a; 26513 漏洞描述&#xff1a; 金…

[Linux] MySQL数据表(数据结构)管理

一、数据库 1.1 数据库的基本概念 数据库&#xff08;database&#xff09;是用来组织、存储和管理数据的仓库 数据库管理系统&#xff08;DBMS&#xff09;&#xff1a;是实现对数据有效组织&#xff0c;管理和存取的系统软件。 数据的建立和维护功能&#xff0c;数据定义…

重温经典struts1之自定义类型转换器及注册的两种方式(Servlet,PlugIn)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 Struts的ActionServlet接收用户在浏览器发送的请求&#xff0c;并将用户输入的数据&#xff0c;按照FormBean中定义的数据类型&#xff0c;赋值给FormBean中每个变量&a…

java多线程创建的三种方式

第一种 第二种 第三种&#xff08;想获得线程的执行结果&#xff0c;建议使用这种&#xff09;

STM32的以太网外设+PHY(LAN8720)使用详解(3):PHY寄存器详解

0 工具准备 1.野火 stm32f407霸天虎开发板 2.LAN8720数据手册 3.STM32F4xx中文参考手册1 PHY寄存器 前面介绍到&#xff0c;站管理接口&#xff08;SMI&#xff09;允许应用程序通过2线时钟和数据线访问任意PHY寄存器&#xff0c;同时该接口支持访问最多32个PHY&#xff0c;也…

口碑好的国产主食冻干猫粮品牌有哪些?盘点十大放心猫粮国产名单

冻干猫粮可以帮助猫咪摄入更多的水分&#xff0c;因为冻干是高蛋白质的食物&#xff0c;当猫咪吃了冻干猫粮后&#xff0c;会感到口渴&#xff0c;从而更主动地去喝水。对于那些不喜欢喝水的猫咪&#xff0c;可以将冻干复水后再喂给它们&#xff0c;这样也可以增加猫咪的水分摄…

【toolschain algorithm cpp ros】cpp工厂模式实现--后续填充具体规划算法,控制器版的已填充了算法接入了仿真器

写在前面 现在局势危机&#xff0c;于是想复习一下之前写的设计模式&#xff0c;之前提到&#xff0c;做过一个闭环仿真器&#xff08;借用ros&#xff09;&#xff0c;见https://blog.csdn.net/weixin_46479223/article/details/134864123我的控制器的建立遵循了工厂模式&…