Ant Design Vue 表格复杂数据合并单元格

Ant Design Vue 表格复杂数据合并单元格

官方合并效果

在这里插入图片描述

官方示例

表头只支持列合并,使用 column 里的 colSpan 进行设置。
表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。

<template><a-table :columns="columns" :data-source="data" bordered><template slot="name" slot-scope="text"><a>{{ text }}</a></template></a-table>
</template>
<script>
// In the fifth row, other columns are merged into first column
// by setting it's colSpan to be 0
const renderContent = (value, row, index) => {const obj = {children: value,attrs: {},};if (index === 4) {obj.attrs.colSpan = 0;}return obj;
};const data = [{key: '1',name: 'John Brown',age: 32,tel: '0571-22098909',phone: 18889898989,address: 'New York No. 1 Lake Park',},{key: '2',name: 'Jim Green',tel: '0571-22098333',phone: 18889898888,age: 42,address: 'London No. 1 Lake Park',},{key: '3',name: 'Joe Black',age: 32,tel: '0575-22098909',phone: 18900010002,address: 'Sidney No. 1 Lake Park',},{key: '4',name: 'Jim Red',age: 18,tel: '0575-22098909',phone: 18900010002,address: 'London No. 2 Lake Park',},{key: '5',name: 'Jake White',age: 18,tel: '0575-22098909',phone: 18900010002,address: 'Dublin No. 2 Lake Park',},
];export default {data() {const columns = [{title: 'Name',dataIndex: 'name',customRender: (text, row, index) => {if (index < 4) {return <a href="javascript:;">{text}</a>;}return {children: <a href="javascript:;">{text}</a>,attrs: {colSpan: 5,},};},},{title: 'Age',dataIndex: 'age',customRender: renderContent,},{title: 'Home phone',colSpan: 2,dataIndex: 'tel',customRender: (value, row, index) => {const obj = {children: value,attrs: {},};if (index === 2) {obj.attrs.rowSpan = 2;}// These two are merged into above cellif (index === 3) {obj.attrs.rowSpan = 0;}if (index === 4) {obj.attrs.colSpan = 0;}return obj;},},{title: 'Phone',colSpan: 0,dataIndex: 'phone',customRender: renderContent,},{title: 'Address',dataIndex: 'address',customRender: renderContent,},];return {data,columns,};},
};
</script>

实际项目中实现效果

在这里插入图片描述

实现原理

分层说明

  1. 数据预处理

    • 使用prepareData方法按markId字段分组
    • 组内数据按mergeIs字段排序(值为"是"的排在前)
  2. 双层级合并机制

    • 主合并层:相同markId的"名称"列合并
    • 次级合并层:在相同markId组内,连续mergeIs === '是’的"数量"列合并
  3. 合并标识管理

    • 通过rowSpan属性控制行合并数
    • rowSpan=0表示该单元格被合并
    • originalIndex记录原始位置用于合并定位
  4. 动态计数器机制

    • primarySpan跟踪名称列合并跨度
    • secondarySpan跟踪数量列合并跨度
    • 遇到分组边界或状态变化时重置计数器
{markId: "分组标识",  // 用于主合并层级mergeIs: "是/否",   // 用于次级合并层级name: "显示内容",    // 名称列数据num: "数值"         // 数量列数据
}

数据流向示意图

分组排序
原始数据
预处理模块
结构优化数据
合并处理器
可合并数据集
表格渲染

表格组件配置

<template><section class="console-section-box"><div class="con"><a-table:columns="columns":data-source="tableData":showHeader="true":loading="tableLoading":pagination="pagination":bordered="true":rowKey="(record, index) => {return index;}":scroll="{ x: true }"></a-table></div><a-back-top /></section>
</template>

合并逻辑

<script>
import { mockData } from '~/mock/index.js';
const productColumn = [{title: '名称',dataIndex: 'name',customRender: (value, row, index) => {const { rowSpan, originalIndex } = row.nameCellObj || { rowSpan: 1, originalIndex: index };const obj = {children: value,attrs: {}};if (index === originalIndex) {obj.attrs.rowSpan = rowSpan;obj.attrs.colSpan = 1;}return obj;},align: 'center',width: 90},{title: '类型',dataIndex: 'type',align: 'center',width: 100},{title: '数量',dataIndex: 'num',key: 'num',customRender: (value, row, index) => {const { rowSpan, originalIndex } = row.numCellObj || { rowSpan: 1, originalIndex: index };const obj = {children: value,attrs: {}};if (index === originalIndex) {obj.attrs.rowSpan = rowSpan;obj.attrs.colSpan = 1;}return obj;},align: 'center',width: 90}
];
export default {name: '',data() {return {tableLoading: false,tableData: [],pagination: {current: 1, // 当前页码pageSize: 10000, // 每页显示条数total: 0,showTotal: total => `共有 ${total} 条数据` //分页中显示总的数据},columns: productColumn,};},async mounted() {await this.fetchData();},methods: {async fetchData() {this.tableLoading = true;try {const res = await this.XXXX();if (res.code === 0) {this.tableData = mockData;this.pagination.total = res.data.length;this.handleCellMerge(this.tableData);}} catch (error) {console.error('Error fetching data:', error);}this.tableLoading = false;},// 根据数据合并单元格handleCellMerge(arr) {if (!arr?.length) return;const processor = {currentMarkId: null,currentMergeIs: null,primarySpan: 1,secondarySpan: 1,// 初始化单元格状态initialize(row, index) {row.nameCellObj = { rowSpan: 1, originalIndex: index };row.numCellObj = { rowSpan: 1, originalIndex: index };},// 主合并逻辑processPrimary(index, rows) {if (rows[index].markId === this.currentMarkId) {this.primarySpan++;rows[index - this.primarySpan + 1].nameCellObj.rowSpan = this.primarySpan;rows[index].nameCellObj.rowSpan = 0;return true;}this.currentMarkId = rows[index].markId;this.primarySpan = 1;return false;},// 次级合并逻辑processSecondary(index, rows) {if (rows[index].mergeIs === this.currentMergeIs && this.currentMergeIs === '是') {this.secondarySpan++;rows[index - this.secondarySpan + 1].numCellObj.rowSpan = this.secondarySpan;rows[index].numCellObj.rowSpan = 0;return true;}this.currentMergeIs = rows[index].mergeIs;this.secondarySpan = 1;return false;}};const sortedData = this.prepareData(arr);processor.currentMarkId = sortedData[0].markId;processor.currentMergeIs = sortedData[0].mergeIs;// 单次遍历处理所有合并逻辑sortedData.forEach((item, index) => {processor.initialize(item, index);if (index === 0) return;if (processor.processPrimary(index, sortedData)) {processor.processSecondary(index, sortedData);} else {processor.currentMergeIs = item.mergeIs;}});arr.splice(0, arr.length, ...sortedData);},// 分组排序方法prepareData(originData) {// 使用Map提高分组性能const groups = new Map();for (const item of originData) {const group = groups.get(item.markId) || [];group.push(item);groups.set(item.markId, group);}// 预计算排序权重避免重复计算return Array.from(groups.values()).flatMap(group => group.sort((a, b) => (b.mergeIs === '是') - (a.mergeIs === '是')));}}
};
</script>

mock数据

mock/index.js

export const mockData = [{name: '数据A',num: '9999999',type: 'AAA',mergeIs: '是',markId: 'ITEM_001'},{name: '数据A',num: '9999999',type: 'BBB',mergeIs: '是',markId: 'ITEM_001'},{name: '数据A',num: '9999999',type: 'CCC',mergeIs: '否',markId: 'ITEM_001'},{name: '数据A',num: '9999999',type: 'DDD',mergeIs: '否',markId: 'ITEM_001'},{name: '数据A',num: '9999999',type: 'EEE',mergeIs: '否',markId: 'ITEM_001'},{name: '数据B',num: '600',type: 'AAA',mergeIs: '是',markId: 'ITEM_002'},{name: '数据B',num: '9999999',type: 'BBB',mergeIs: '否',markId: 'ITEM_002'},{name: '数据B',num: '600',type: 'CCC',mergeIs: '是',markId: 'ITEM_002'},{name: '数据B',num: '9999999',type: 'DDD',mergeIs: '否',markId: 'ITEM_002'},{name: '数据B',num: '9999999',type: 'EEE',mergeIs: '否',markId: 'ITEM_002'},{name: '数据C',num: '9999999',type: 'AAA',mergeIs: '否',markId: 'ITEM_003'},{name: '数据C',num: '9999999',type: 'BBB',mergeIs: '否',markId: 'ITEM_003'},{name: '数据C',num: '9999999',type: 'CCC',mergeIs: '否',markId: 'ITEM_003'},{name: '数据C',num: '9999999',type: 'DDD',mergeIs: '否',markId: 'ITEM_003'},{name: '数据C',num: '9999999',type: 'EEE',mergeIs: '否',markId: 'ITEM_003'}
];

5. 样式

<style lang="scss" scoped>
.con {min-height: calc(100vh - 160px);padding: 24px;border-radius: 8px;background-color: #fff;
}
.project-info-box {display: flex;flex-direction: column;width: 100%;height: 100%;padding-bottom: 20px;
}
.project-info {width: 100%;height: 60px;line-height: 60px;display: flex;justify-content: space-between;p {margin: 0;}
}
</style>

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

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

相关文章

C++ 标准库中的 <algorithm> 头文件算法总结

C 常用 <algorithm> 算法概览 C 标准库中的 <algorithm> 头文件提供了大量有用的算法&#xff0c;主要用于操作容器&#xff08;如 vector, list, array 等&#xff09;。这些算法通常通过迭代器来操作容器元素。 1. 非修改序列操作 std::all_of, std::any_of, s…

程序化广告行业(84/89):4A广告代理公司与行业资质解读

程序化广告行业&#xff08;84/89&#xff09;&#xff1a;4A广告代理公司与行业资质解读 大家好&#xff01;在探索程序化广告行业的道路上&#xff0c;每一次知识的分享都是我们共同进步的阶梯。一直以来&#xff0c;我都希望能和大家携手前行&#xff0c;深入了解这个充满机…

deepin使用autokey添加微信快捷键一键显隐ctrl+alt+w

打开deepin商店&#xff0c;搜索快捷键&#xff0c;找到autokey 快捷键管理&#xff0c;点击安装 点击右键新建文件夹 点击右键新建脚本 打开脚本并添加以下内容 import subprocess import time# ------------------ 配置项 ------------------ WM_CLASS "wechat…

文件内容课堂总结

Spark SQL是Spark用于结构化数据处理的模块&#xff0c;前身是Shark。Shark基于Hive开发&#xff0c;虽提升了SQL-on-Hadoop效率&#xff0c;但对Hive依赖过多。2014年6月1日Shark项目停止开发&#xff0c;团队将资源投入Spark SQL项目。Spark SQL具有诸多优点&#xff0c;如摆…

Zotero PDF Translate 翻译插件使用OpenAI API配置教程

PDF Translate&#xff1a;提升 Zotero 内置 PDF 阅读器的翻译功能 “PDF Translate” 是一款为 Zotero 设计的插件&#xff0c;旨在方便用户在 Zotero 内置的 PDF 阅读器中进行划词或段落翻译&#xff0c;辅助阅读外文文献。 一、 安装插件 下载插件&#xff1a; 访问 PDF T…

火山引擎旗下的产品

用户问的是火山引擎旗下的产品&#xff0c;我需要详细列出各个类别下的产品。首先&#xff0c;我得确认火山引擎有哪些主要业务领域&#xff0c;比如云计算、大数据、人工智能这些。然后&#xff0c;每个领域下具体有哪些产品呢&#xff1f;比如云计算方面可能有云服务器、容器…

C/C++程序中实现Python绑定多种技术路线

在C/C程序中实现Python绑定有多种技术路线&#xff0c;选择合适的方法取决于项目需求、性能要求和开发效率。以下是常见的几种方案&#xff0c;按易用性排序&#xff1a; 1. PyBind11&#xff08;推荐首选&#xff09; 特点&#xff1a;现代C库&#xff0c;语法简洁&#xff0…

【位运算】消失的两个数字

文章目录 面试题 17.19. 消失的两个数字解题思路 面试题 17.19. 消失的两个数字 面试题 17.19. 消失的两个数字 ​ 给定一个数组&#xff0c;包含从 1 到 N 所有的整数&#xff0c;但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗&#xff1f; ​ 以任意…

自然语言处理Hugging Face Transformers

Hugging Face Transformers 是一个基于 PyTorch 和 TensorFlow 的开源库&#xff0c;专注于 最先进的自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;如 BERT、GPT、RoBERTa、T5 等。它提供了 预训练模型、微调工具和推理 API&#xff0c;广泛应用于文本分类、机器翻…

vue开发基础流程 (后20)

创建项目命令&#xff1b; 或者 vue create my - vue - router - project这个是创建带路由的项目 22.组件组成 比如说一个页面吧&#xff0c;他三个组件&#xff0c;template就是用来放所有的标签&#xff0c;script用来放业务逻辑&#xff0c;style用来放样式&#xff0c;c…

高性能内存kv数据库Redis

引言 在当今数据驱动的时代&#xff0c;高效的数据存储和检索对于各类应用程序至关重要。Redis&#xff08;Remote Dictionary Server&#xff09;作为一款开源的内存键值数据库&#xff0c;凭借其出色的性能、丰富的数据结构和灵活的特性&#xff0c;在众多场景中得到了广泛应…

自动化测试概念篇

文章目录 目录1. 自动化1.1 自动化概念1.1.1 回归测试 1.2 自动化分类1.3 自动化测试金字塔 2. web自动化测试2.1 驱动2.1.1 安装驱动管理2.1.2 selenium库 3. Selenium3.1 一个简单的web自动化示例3.2 selenium驱动浏览器的工作原理 目录 自动化web自动化测试Selenium 1. 自…

《AI大模型应知应会100篇》第17篇:大模型的偏见与公平性问题

第17篇&#xff1a;大模型的偏见与公平性问题 摘要 在人工智能迅速发展的今天&#xff0c;大型语言模型&#xff08;LLM&#xff09;已经深入到我们的日常生活和工作中。然而&#xff0c;这些模型并非完美无缺&#xff0c;它们可能携带并放大数据中的偏见&#xff0c;导致不公…

【踩坑】GitHub Actions 运行的 Linux 环境中,文件名是大小写敏感的

在使用 VuePress 搭建个人博客并部署到 GitHub Pages 的过程中&#xff0c;我遇到了一个颇为棘手的问题&#xff1a;本地打包一切正常&#xff0c;但在 GitHub Actions 自动执行打包流程时&#xff0c;却提示找不到 README.md 文件&#xff0c;导致整个流程失败。经过一番深入排…

C# 13新特性 - .NET 9

转载&#xff1a; C# 13 中的新增功能 | Microsoft Learn C# 13 包括以下新增功能。 可以使用最新的 Visual Studio 2022 版本或 .NET 9 SDK 尝试这些功能&#xff1a;Introduced in Visual Studio 2022 Version 17.12 and newer when using C# 13 C# 13 中的新增功能 | Micr…

numpy.ma.masked_where:屏蔽满足条件的数组

1.函数功能 屏蔽满足条件的数组内容&#xff0c;返回值为掩码数组 2.语法结构 np.ma.masked_where(condition, a, copyTrue)3. 参数 参数含义condition屏蔽条件a要操作的数组copy布尔值&#xff0c;取值为True时&#xff0c;结果复制数组(原始数据不变)&#xff0c;否则返回…

【Redis】数据结构和内部编码

先来复习一下之前学过的几个基本的全局命令&#xff1a; keys&#xff1a;用来查看匹配规则的keyexists&#xff1a;用来判定执行key是否存在del&#xff1a;删除指定的keyexpire&#xff1a;给key设置过期时间ttl&#xff1a;查询key的过期时间type&#xff1a;查询key对应的…

OBOO鸥柏如何以智能教育室内外触摸屏一体机AI变革硬件

在AI技术蓬勃发展的当下&#xff0c;OBOO鸥柏室外触摸屏一体机通过融入AI科技&#xff0c;为教育领域带来了翻天覆地的变化。这款一体机不仅为高校和大学校园提供了革命性的数字化教学解决方案&#xff0c;更引领了引体向上成绩提升一体机带训室外终端屏幕设备的新潮流。其创新…

从零搭建高并发体育直播网站:架构设计、核心技术与性能优化实战

本文从技术视角拆解体育直播网站开发全流程&#xff0c;涵盖高并发架构设计、低延迟视频流传输、实时弹幕系统实现等核心模块&#xff0c;并附可复用的代码片段与优化方案。适合中高级开发者进阶实战参考。 一、需求分析与技术选型 1. 典型业务场景 核心需求&#xff1a;支持1…

【Python内置函数的深度解析与应用】id

目录 前言&#xff1a;技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解关键技术模块技术选型对比 二、实战演示环境配置要求核心代码实现1. 基础身份验证2. 不可变对象优化3. 对象生命周期追踪 运行结果验证 三、性能对比测试方法论量化数据…