vue3+ts+elementui-表格根据相同值合并

代码

 <div style="height: auto; overflow: auto"><el-table ref="dataTableRef" v-loading="loading" :data="pageData" highlight-current-row border@selection-change="handleSelectionChange" :span-method="objectSpanMethod" :row-style="tableRowStyle"><el-table-column type="selection" width="55" align="center" /><!-- <el-table-column key="id" label="id" prop="id" align="center" /> --><el-table-column key="roomName" label="房间名称" prop="roomName" align="center" /><el-table-column key="categoryName" label="所属分类" prop="categoryName" align="center" /><el-table-column key="deviceName" label="设备名称" prop="deviceName" align="center" /></el-table><pagination v-if="total > 0" v-model:total="total" v-model:page="queryParams.pageNum"v-model:limit="queryParams.pageSize" @pagination="handleQuery()" style="float: right;" /></div>

js 


interface User {id: stringroomName: stringdeviceName: stringcategoryName: string
}
interface SpanMethodProps {row: Usercolumn: TableColumnCtx<User>rowIndex: numbercolumnIndex: number
}
const objectSpanMethod = ({ row, column, rowIndex }) => {if (column.property === 'roomName') {const currentRoom = row.roomName;let prevRoom = rowIndex === 0 ? null : pageData.value[rowIndex - 1].roomName;if (rowIndex === 0 || currentRoom !== prevRoom) {let count = 1;for (let i = rowIndex + 1; i < pageData.value.length; i++) {if (pageData.value[i].roomName === currentRoom) {count++;} else {break;}}return { rowspan: count, colspan: 1 };} else {return { rowspan: 0, colspan: 0 };}}if (column.property === 'categoryName') {const currentCategory = row.categoryName;let prevCategory = rowIndex === 0 ? null : pageData.value[rowIndex - 1].categoryName;if (rowIndex === 0 || currentCategory !== prevCategory) {let count = 1;for (let i = rowIndex + 1; i < pageData.value.length; i++) {if (pageData.value[i].categoryName === currentCategory) {count++;} else {break;}}return { rowspan: count, colspan: 1 };} else {return { rowspan: 0, colspan: 0 };}}return { rowspan: 1, colspan: 1 };
}
// 定义合并信息的类型
type SpanInfo = {rowspan: numbercolspan: number
}// 用于存储 roomName 和 categoryName 的合并信息
const roomNameSpanMap: Map<number, SpanInfo> = new Map() // key 是 rowIndex
const categoryNameSpanMap: Map<number, SpanInfo> = new Map()// 计算合并信息的方法
const calculateSpans = (data: User[]) => {let roomNameCount = 1let categoryNameCount = 1let prevRoomName = data[0]?.roomNamelet prevCategoryName = data[0]?.categoryName// 第一行默认 rowspan 为后续相同项的数量roomNameSpanMap.set(0, { rowspan: 1, colspan: 1 })categoryNameSpanMap.set(0, { rowspan: 1, colspan: 1 })for (let i = 1; i < data.length; i++) {const current = data[i]const prev = data[i - 1]// 处理 roomNameif (current.roomName === prev.roomName) {roomNameCount++// 当前行不显示,rowspan 设为 0roomNameSpanMap.set(i, { rowspan: 0, colspan: 0 })} else {// 新的 roomName,设置 rowspan 为累计的数量roomNameSpanMap.set(i - 1, { rowspan: roomNameCount, colspan: 1 })roomNameCount = 1 // 重置计数roomNameSpanMap.set(i, { rowspan: 1, colspan: 1 }) // 当前行可能是新的开始}// 处理 categoryNameif (current.categoryName === prev.categoryName) {categoryNameCount++categoryNameSpanMap.set(i, { rowspan: 0, colspan: 0 })} else {categoryNameSpanMap.set(i - 1, { rowspan: categoryNameCount, colspan: 1 })categoryNameCount = 1categoryNameSpanMap.set(i, { rowspan: 1, colspan: 1 })}prevRoomName = current.roomNameprevCategoryName = current.categoryName}// 处理最后一行的 rowspanroomNameSpanMap.set(data.length - 1, { rowspan: roomNameCount, colspan: 1 })categoryNameSpanMap.set(data.length - 1, { rowspan: categoryNameCount, colspan: 1 })
}
const tableRowStyle = ({ row, rowIndex }) => {return {height: '40px','vertical-align': 'middle'}
}

style 

// 表格
/* 确保表格行高一致,避免合并后行高错乱 */
:deep(.el-table .el-table__row) {/* 不要设置height/min-height/line-height,自动撑开 */vertical-align: middle !important;
}:deep(.el-table__cell) {vertical-align: middle !important;
}/* 确保表格容器有足够的空间 */
:deep(.table-container) {height: auto;/* 自动高度 */overflow: auto;/* 如果内容超出,显示滚动条 */
}

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

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

相关文章

UI前端与数字孪生融合案例:智慧城市的智慧停车引导系统

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩!一、引言&#xff1a;停车难的 “城市痛点” 与数字孪生的破局之道当司机在商圈绕圈 30 分钟仍…

java+vue+SpringBoot集团门户网站(程序+数据库+报告+部署教程+答辩指导)

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿ppt部署教程代码讲解代码时间修改工具 技术实现 开发语言&#xff1a;后端&#xff1a;Java 前端&#xff1a;vue框架&#xff1a;springboot数据库&#xff1a;mysql 开发工具 JDK版本&#xff1a;JDK1.8 数…

【Docker基础】Docker-compose从入门到精通:安装指南与核心命令全解析

目录 前言 1 Docker-compose核心概念解析 1.1 什么是Docker-compose&#xff1f; 1.2 典型应用场景 2 Docker-compose离线安装详解 2.1 离线安装背景与优势 2.2 详细安装步骤 步骤1&#xff1a;获取离线安装包 步骤2&#xff1a;文件部署与权限设置 步骤3&#xff1a…

面试150 被围绕的区域

思路 使用DFS&#xff0c;将所有与边界相连的’O’都修改为‘#’,然后遍历数组&#xff0c;如果是遇到’#‘修改为’O’,如果是’O’修改为’X’。 class Solution:def solve(self, board: List[List[str]]) -> None:"""Do not return anything, modify boar…

(数据结构)线性表(上):SeqList 顺序表

线性表&#xff08;上&#xff09;&#xff1a;Seqlist 顺序表基本了解线性表顺序表静态顺序表动态顺序表编写动态顺序表项目结构基础结构初始化尾插头插尾删头删查找指定位置pos之前插入数据删除指定位置pos的数据销毁完整代码SeqLIst.hSeqLIst.ctest.c算法题移除元素删除有序…

WebStorm vs VSCode:前端圈的「豆腐脑甜咸之争」

目录 一、初识两位主角&#xff1a;老司机与新势力 二、开箱体验&#xff1a;是「拎包入住」还是「毛坯房改造」 三、智能提示&#xff1a;是「知心秘书」还是「百度搜索」 四、调试功能&#xff1a;是「CT 扫描仪」还是「听诊器」 五、性能表现&#xff1a;是「重型坦克」…

C#将类属性保存到Ini文件方法(利用拓展方法,反射方式获取到分组名和属性名称属性值)

前言&#xff1a;最近学习C#高级课程&#xff0c;里面学到了利用反射和可以得到属性的特性、属性名、属性值&#xff0c;还有拓展方法&#xff0c;一直想将学到的东西利用起来&#xff0c;刚好今天在研究PropertyGrid控件时&#xff0c;想方便一点保存属性值到配置文件&#xf…

kafka 单机部署指南(KRaft 版本)

目录环境准备JDK安装下载jdkjdk安装kafka 部署kafka 下载kafka 版本号结构解析kafka 安装下载和解压安装包配置 KRaft 模式格式化存储目录启动kafkaKafka 配置为 systemd 服务注意事项调整 JVM 内存参数Kafka KRaft 版本&#xff08;即 Kafka 3.0 及更高版本&#xff09;使用 K…

websocket案例 599足球比分

目标地址:aHR0cHM6Ly93d3cuNTk5LmNvbS9saXZlLw接口:打开控制台 点websocket 刷新页面 显示分析:不写理论了关于websocket 几乎发包位置都是下方图片 不管抖音还是快手 等平台这里在进行 new WebSocket 后 是要必须走一步的 也就是 new WebSocket().onopen() 也就是onopen 进行向…

【后端】Linux系统发布.NetCore项目

目录 1.设置全球化不变模式 1.发布到文件 3. 配置为服务 3.1.添加服务 3.2.添加执行权限 3.3.启动服务 4.访问 1.设置全球化不变模式 双击所需项目&#xff0c;设置全球化不变模式 <!-- 设置全球化不变模式 --><RuntimeHostConfigurationOption>System.Globa…

CMU-15445(2024fall)——PROJECT#0

题目介绍 这是题目原文。 注意&#xff1a;在拉取项目的时候需要注意拉取2024fall的Tag&#xff0c;本人血泪教训&#xff01; 本题是关于HyperLogLog的具体实现&#xff0c;其介绍可以看这个视频进行了解。简单来说HyperLogLog可以在一个非常小的固定内存下&#xff08;一般…

使用微信免费的图像处理接口,来开发图片智能裁剪和二维码/条码识别功能,爽歪歪

大家好&#xff0c;我是小悟。 1、图片智能裁剪 我们先来了解一下图片智能裁剪。图片智能裁剪聚焦于数字图像的智能化处理。AI技术的引入彻底改变了传统依赖人工框选的裁剪模式。 通过深度学习模型自动识别图像主体&#xff08;人物、商品等&#xff09;&#xff0c;能在极短时…

【代码随想录】+ leetcode hot100:栈与队列算法专题总结、单调栈

大家好&#xff0c;我是此林。 今天分享的是【代码随想录】栈与队列算法专题总结&#xff0c;分享刷算法的心得体会。 1. 用栈实现队列、用队列实现栈 232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09; 225. 用队列实现栈 - 力扣&#xff08;LeetCode&#xff09;…

《5分钟开发订单微服务!飞算JavaAI实战:IDEA插件安装→空指针修复→K8s部署全流程》

目录 40倍提升开发效能的秘密武器 一、为什么选择飞算JavaAI&#xff1f;​编辑 二、IDEA插件安装三步曲&#xff08;极简版&#xff09; 步骤1&#xff1a;安装插件&#xff08;30秒完成&#xff09; 步骤2&#xff1a;账号登录&#xff08;2种方式任选&#xff09; 方式…

SQL注入基础尝试

进入网址&#xff0c;测试正常回显和出错画面http://1bcf75af-6e69-4f78-ac71-849fb8cde1b5.node5.buuoj.cn/Less-2/? id1用特殊符号判断注入点判断其类型类型为数字型&#xff0c;order by判断列数当数字为4时候报错而3不报错&#xff0c;由此推断列数为3&#xff0c;接着测试…

[Dify] -进阶4-在 Dify 中实现 PDF 文档问答功能全流程

随着业务需求增加,AI 应用常遇到让模型“读懂”PDF并回答问题的场景。借助 Dify 的 RAG(Retrieval‑Augmented Generation)能力,我们可以构建一个“ChatPDF”式的互动问答机器人。本文详细讲解从环境搭建、PDF 上传、文本抽取、向量检索到问答部署的完整流程。 一、技术栈与…

【EPLAN 2.9】许可证xx成功却显示红色叉,无法启动

问题现象&#xff1a; 无法启动。 原因&#xff1a;通过mstsc远程桌面连接会占用显卡&#xff0c;导致调用显卡的软件无法成功。参考&#xff1a;Windows自带远程桌面(mstsc)在远程时无法启动&#xff08;打开&#xff09;某些应用&#xff08;软件&#xff09;的解决办法 编写…

Oracle ADG 一键自动化搭建脚本

前言在 Oracle 数据库高可用架构中&#xff0c;Active Data Guard (ADG) 是保障数据安全和业务连续性的核心方案。然而传统 ADG 搭建涉及数十项复杂配置&#xff08;监听、TNSNAMES、参数文件、密码文件、日志传输、应用服务等&#xff09;&#xff0c;步骤繁琐且易错&#xff…

某邮生活旋转验证码识别

注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架 本文识别已同步上线至OCR识别网站: http://yxlocr.nat300.top/ocr/other/30 旋转验证码数据集如下: 看起来很像顶象的,都有着绿边干扰,那其实思路也能简单了,…

基于Android的景点旅游信息系统App

项目介绍用户分为普通用户和管理员两种角色。 1.管理员有用户管理、景点管理、评论管理功能。 2.用户管理包括查看已注册用户列表、删除用户&#xff1b; 3.景点管理包括增加景点信息、修改景点信息、删除景点信息、将景点设为推荐&#xff1b; 4.评论管理包括查看评论内容、删…