当前位置: 首页 > news >正文

Vue3(递归组件) + 原生Table 实现树结构复杂表格

一、递归组件

什么是递归,Javascript中经常能接触到递归函数。也就是函数自己调用自己。那对于组件来说也是一样的逻辑。平时工作中见得最多应该就是菜单组件,大部分系统里面的都是递归组件。文章中我做了按需引入的配置,所以看不到我引用组件、Vue3的相关API等等。需要了解的小伙伴可以看我的另一篇文章 Vite4+Pinia2+vue-router4+ElmentPlus搭建Vue3项目(组件、图标等按需引入)

二、Table的合并

复杂的表格无非就是行或者列的合并。主要涉及到colspan和rowspan。colspan属性规定单元格可横跨的列数。rowspan属性规定单元格可横跨的行数。比如下面的列子。第一行为标题。表格最多为5列。所以第一行的列需要全部合并,colspan的值就为5。第三行和第四行都是统一的食品分类,需要合并,所以第三行的第一列就需要往下合并。往下合并两行,所以rouspan就为2。但是这里要注意,列合并不用管。行的话被合并的列就需要删除。是不是很简单。两个设置就能实现下面的列子。

<template><table class="table"><tr><td colspan="5">某某小卖部</td></tr><tr><td>商品分类</td><td>商品</td><td>价格</td><td>库存</td><td>描述</td></tr><tr><td rowspan="2">食品</td><td>瓜子</td><td>5元</td><td>20</td><td>可以吃的瓜子</td></tr><tr><td>花生</td><td>6元</td><td>30</td><td>可以吃的花生</td></tr></table>
</template><style lang="scss">
.table {width: 100%;margin-left: 0;text-align: center;font-size: 12px;
}.table th,
.table td {border: 1px solid #070707 !important;padding: 0.35rem !important;font-size: 16px;vertical-align: middle !important;
}.ts-table-bold {td {font-weight: bold;font-size: 18px;}
}
</style>

三、核心方法

核心的方法主要就是行和列的合并规则,不管是我现在这个表格还是其他复杂的,只要你细心的观察。总会发现规则。然后就能利用js去实现。

因为需要知道树结构总共拥有多少节点,树结构有多少层级。我在列子中也用到了递归函数。比如下面的树结构转平行结构。参数tree的话表示树节点。第二个list表示我需要存储对象,第三个参数表示父节点的id。

// 获取整个树数据的长度  用于行的合并
const treeToList = (tree: TreeType[], list: TreeType[], parentId: string | null) => {for (let i in tree) {const nodeData = tree[i];list.push({id: nodeData.id,title: nodeData.title,parentId: parentId});if (nodeData.children && nodeData.children.length !== 0) {treeToList(nodeData.children, list, nodeData.id)}}
}

三、组件的封装完整代码

上面的列子是写死的,所以实现起来比较的简单,接下来就需要获取动态的数据,动态进行行或者列的合并实现复杂的表格展示。组件中props里面的参数:data就是数据源,level表示整个数据的层级,currentLevel表示当前递归到第几层。

<template><tr v-if="!data.children || data.children.length === 0"><td :colspan="(level - currentLevel + 1) / 2">{{ data.title }}</td></tr><tr v-else><td :rowspan="getTreeToArr(data.children) + 1">{{ data.title }}</td></tr><template v-for="it in data.children" :key="it.id"><ts-recursion-table :data="it" :level="level" :currentLevel="currentLevel + 1" /></template>
</template><script lang="ts">type TreeType = {title: stringid: stringparentId: string | nullchildren?: Array<TreeType>
}export default defineComponent({name: 'TsRecursionTable',props: ['data', 'level', 'currentLevel'],setup() {// 获取整个树数据的长度  用于行的合并const treeToList = (tree: TreeType[], list: TreeType[], parentId: string | null) => {for (let i in tree) {const nodeData = tree[i];list.push({id: nodeData.id,title: nodeData.title,parentId: parentId});if (nodeData.children && nodeData.children.length !== 0) {treeToList(nodeData.children, list, nodeData.id)}}}const getTreeToArr = (data: any) => {let result:TreeType[] = []if (!data) {return 0}treeToList(data, result,null)return result.length}return {getTreeToArr}}
})
</script>

四、组件的使用完整代码

<template><div style="width: 1000px;margin: 200px auto auto auto;"><table class="table"><tr><td :colspan="level">某某区人数统计</td></tr><ts-recursion-table v-for="(item, index) in tableData" :key="item.id" :data="item" :level="level" :currentLevel="1" /></table></div>
</template><script lang="ts">type TreeType = {title: stringid: stringparentId: string | nullchildren?: Array<TreeType>
}export default defineComponent({setup() {const rowLength = ref<number>(0)const level = ref<number>(0)const state = reactive({tableData: [{title: '社区一',id: '1',parentId: null,children: [{title: '街道一',id: '1-1',parentId: '1',children: [{id: '1-1-1',parentId: '1-1',title: '小区1',children: [{id: '1-1-1-1',parentId: '1-1-1',title: '单元1',children: [{id: '1-1-1-1-1',parentId: '1-1-1-1',title: '住户1'},{id: '1-1-1-1-2',parentId: '1-1-1-1',title: '住户2'}]},{id: '1-1-1-2',parentId: '1-1-1',title: '单元2'},]},{id: '1-1-2',parentId: '1-1',title: '小区2'},]},{title: '街道二',id: '1-2',parentId: '1',children: [{id: '1-2-1',parentId: '1-2',title: '小区1'},{id: '1-2-2',parentId: '1-2',title: '小区2'}]}]},{title: '社区二',id: '2',parentId: null,children: [{title: '街道一',id: '2-1',parentId: '2',children: [{id: '2-1-1',parentId: '2-1',title: '小区1'},{id: '2-1-2',parentId: '2-1',title: '小区2'},{id: '2-1-3',parentId: '2-1',title: '小区3'},]}]}] as TreeType[]})// 获取整个树数据的长度  用于行的合并const treeToList = (tree: TreeType[], list: TreeType[], parentId: string | null) => {for (let i in tree) {const nodeData = tree[i];list.push({id: nodeData.id,title: nodeData.title,parentId: parentId});if (nodeData.children && nodeData.children.length !== 0) {treeToList(nodeData.children, list, nodeData.id)}}}// 获取整个树数据的层级 用于列的合并const getTreeLevel = (arr: TreeType[]) => {let maxLevel = 0;(function callBack(arr, level) {++level;maxLevel = Math.max(level, maxLevel);for (let i = 0; i < arr.length; i++) {let item = arr[i];if (item.children && item.children.length > 0) {callBack(item.children, level);} else {delete item.children;}}})(arr, 0);return maxLevel;}onMounted(() => {const list: TreeType[] = []treeToList(state.tableData, list, null)rowLength.value = list.length || 0let length = getTreeLevel(JSON.parse(JSON.stringify(state.tableData)))if (length > 2) {level.value = length * 2} else {level.value = 2}})return {...toRefs(state),rowLength,level}}
})
</script><style lang="scss">
.table {width: 100%;margin-left: 0;text-align: center;font-size: 12px;
}.table th,
.table td {border: 1px solid #070707 !important;padding: 0.35rem !important;font-size: 16px;vertical-align: middle !important;
}.ts-table-bold {td {font-weight: bold;font-size: 18px;}
}
</style>

五、最终效果

因为这里我只是为了做个demo,里面的Type还有公共的方法以及样式都是可以提取出来放到一个公共的文件里面。这个的话自己去完成。其实表格也不算复杂。

我是Etc.End。如果文章对你有所帮助,能否帮我点个免费的赞和收藏😍。同时欢迎各位小伙伴一起学习,一起成长WX:👉SH--TS👈

❤️ 💓 💗 💖 ✨ ⭐️ 🌟 💥 💥

相关文章:

Vue3(递归组件) + 原生Table 实现树结构复杂表格

一、递归组件 什么是递归&#xff0c;Javascript中经常能接触到递归函数。也就是函数自己调用自己。那对于组件来说也是一样的逻辑。平时工作中见得最多应该就是菜单组件&#xff0c;大部分系统里面的都是递归组件。文章中我做了按需引入的配置&#xff0c;所以看不到我引用组…...

ArrayList底层源码解析

Java源码系列&#xff1a;下方连接 http://t.csdn.cn/Nwzed 文章目录前言一、**ArrayList底层结构和源码分析**无参构造调用创建ArrayList集合无参构造总结&#xff1a;发文3个工作日后 up 会把总结放入前言部分&#xff0c;但也诚邀读者总结&#xff0c;可放入评论区有参构造…...

python:DIY字符画的程序使用说明.doc

目录开发环境要求运行方法具体的操作步骤如下&#xff1a;代码示例源码及运行程序下载地址开发环境要求 本系统的软件开发及运行环境具体如下。 操作系统&#xff1a;Windows 7、Windows 10。 Python版本&#xff1a;Python 3.7.0。 开发工具&#xff1a;Python IDLE。 …...

【Python/Opencv】图像权重加法函数:cv2.addWeighted()详解

【Python/Opencv】图像权重加法函数&#xff1a;cv2.addWeighted()详解 文章目录【Python/Opencv】图像权重加法函数&#xff1a;cv2.addWeighted()详解1. 介绍2. API3. 代码示例与效果3.1 代码3.2 效果4. 参考1. 介绍 在OpenCV图像加法cv2.add函数详解详细介绍了图像的加法运…...

容器的老祖宗LXC和Docker的关系

一、什么是LXC&#xff1f; LXC&#xff08;Linux Container的缩写&#xff09;是一个基于Linux内核的容器虚拟化技术&#xff0c;它提供了一种轻量级、快速、简便的方式来创建和管理系统容器。与传统虚拟化技术不同&#xff0c;LXC并不会模拟硬件&#xff0c;而是利用Linux内…...

Webpack迁移Rspack速攻实战教程(前瞻版)

前言 rspack 即将开源&#xff0c;但社区中不乏有已经落地的 case &#xff0c;比如 rspack-migration-showcase 、 modern.js 等。 基于此&#xff0c;本文将介绍如何迁移一个近似于 CRA&#xff08; create-react-app &#xff09; 的项目到 rspack 。 在阅读本文前&#…...

一行代码“黑”掉任意网站

文章目录只需一行代码&#xff0c;轻轻一点就可以把任意网站变成暗黑模式。 首先我们先做一个实验&#xff0c;在任意网站中&#xff0c;打开浏览器开发者工具(F12)&#xff0c;在 C1onsole 控制台输入如下代码并回车&#xff1a; document.documentElement.style.filterinve…...

51单片机入门 -驱动 8x8 LED 点阵屏

硬件型号、软件版本、以及烧录流程 操作系统&#xff1a;Windows 10 x84-64单片机&#xff1a;STC89C52RC编译器&#xff1a;SDCC烧录软件&#xff1a;stcgal 1.6开发板&#xff1a;普中51单片机开发板A2套件&#xff08;2022&#xff09; 在 VS Code 中新建项目到烧录的过程…...

Xinlinx zynq7045国产替代 FMQL45T900全国产化 ARM 核心板+扩展板

TES745D 是一款基于 FMQL45T900 的全国产化 ARM 核心板。该核心板将 FMQL45T900&#xff08;与XC7Z045-2FFG900I 兼容&#xff09;的最小系统集成在了一个 87*117mm 的核心板上&#xff0c;可以作为一个核心模块&#xff0c;进行功能性扩展&#xff0c;能够快速的搭建起一个信号…...

硬刚ChatGPT!文心一言能否为百度止颓?中国版ChatGPT“狂飙”的机会在哪儿?

文章目录目录产品背景发展历程科技简介主要功能合作伙伴结语文心一言 &#xff08;英文名&#xff1a;ERNIE Bot&#xff09; *是百度基于文心大模型技术推出的生成式对话产品&#xff0c;被外界誉为“中国版ChatGPT”&#xff0c;将于2023年3月份面向公众开放。 [40] 百度在人…...

Python 异步: 在非阻塞子进程中运行命令(19)

动动发财的小手&#xff0c;点个赞吧&#xff01; 我们可以从 asyncio 执行命令。该命令将在我们可以使用非阻塞 I/O 写入和读取的子进程中运行。 1. 什么是 asyncio.subprocess.Process asyncio.subprocess.Process 类提供了由 asyncio 运行的子进程的表示。它在 asyncio 程序…...

蓝桥杯嵌入式第五课--输入捕获

前言输入捕获的考题十分明确&#xff0c;就是测量输入脉冲波形的占空比和频率&#xff0c;对我们的板子而言&#xff0c;就是检测板载的两个信号发生器产生的信号&#xff1a;具体来说就是使用PA15和PB4来做输入捕获。输入捕获原理简介输入捕获能够对输入信号的上升沿和下降沿进…...

Spring事务和事务传播机制

目录 Spring中事务的实现 1、通过代码的方式手动实现事务 2、通过注解的方式实现声明式事务 2.1、Transactional作用范围 2.2、Transactional参数说明 2.3、注意事项 2.4、Transactional工作原理 事务隔离级别 1、事务特性 2、Spring中设置事务隔离级别 2.1、MySQL事…...

基于OpenCV+CUDA实时视频抠绿、背景合成以及抠绿算法小结

一、关于抠绿 百度百科上描述抠绿“抠绿是指在摄影或摄像时,以绿色为背景进行拍摄,在后期制作时使用特技机的“色键”将绿色背景抠去,改换其他更理想的背景的技术。”绿幕的使用已经非常普遍,大到好莱坞大片,小到自媒体的节目,一些商业娱乐场景,几乎都用使用。但是很多非…...

MySQL 中的 UNION 语句

文章目录一、数据准备一、UNION 和 UNION ALL二、UNION 的执行顺序&#xff08;UNION 和其他语句一同出现&#xff09;三、MySQL 使用 UNION&#xff08;ALL&#xff09; ORDER 导致排序失效四、UNION 报错语法一、数据准备 -- 创建表 CREATE TABLE test_user (ID int(11) NO…...

高完整性系统工程(三): Logic Intro Formal Specification

目录 1. Propositions 命题 2.1 Propositional Connectives 命题连接词 2.2 Variables 变量 2.3 Sets 2.3.1 Set Operations 2.4 Predicates 2.5 Quantification 量化 2.6 Relations 2.6.1 What Is A Relation? 2.6.2 Relations as Sets 2.6.3 Binary Relations as…...

【linux】多线程概念详述

文章目录一、线程基本概念1.1 进程地址空间与页表1.2 页表结构1.3 线程的理解1.3.1 如何描述线程1.4 再谈进程1.5 代码理解1.5.1 原生库提供线程pthread_create1.6 资源共享问题1.7 资源私有问题二、总结2.1 什么是线程2.2 并行与并发2.3 线程的优点2.4 线程的缺点2.5 线程异常…...

【Java】P8 面向对象(3)方法 基本知识

面向对象 方法方法方法的声明权限修饰符返回值类型方法名形参列表方法体简单案例方法 方法 是对类或对象行为特征的抽象&#xff0c;用来完成某个功能的操作。方法的目的 是为了实现代码复用&#xff0c;减少冗余&#xff0c;简化代码&#xff1b;方法不能独立存在&#xff0c…...

js中null和undefined的区别

js中null和undefined的区别?这也是一个常见的js面试题 相同点 1&#xff0c;都是基本类型。 2&#xff0c;做判断值都是false。 !!null false // true !!undefined false // true不同点 1&#xff0c;诞生时间null在前&#xff0c;undefined在后。因为js作者Brendan-Eic…...

【Linux】linux中的c++怎么调试?gdb的介绍和使用。

背景1.1.前提知识程序的发布方式有两种&#xff0c;debug模式和release模式Linux gcc/g出来的二进制程序&#xff0c;默认是release模式 要使用gdb调试&#xff0c;必须在源代码生成二进制程序的时候, 加上 -g 选项windows上的调试方法有区别吗&#xff1f;1.调试思路是一样的2…...

FlexASIO:打破专业音频壁垒的通用驱动解决方案

FlexASIO&#xff1a;打破专业音频壁垒的通用驱动解决方案 【免费下载链接】FlexASIO A flexible universal ASIO driver that uses the PortAudio sound I/O library. Supports WASAPI (shared and exclusive), KS, DirectSound and MME. 项目地址: https://gitcode.com/gh_…...

Selenium爬虫被检测?3种隐藏WebDriver属性的实战技巧(附最新ChromeDriver配置)

Selenium爬虫被检测&#xff1f;3种隐藏WebDriver属性的实战技巧&#xff08;附最新ChromeDriver配置&#xff09; 在数据采集领域&#xff0c;Selenium一直是处理动态渲染页面的利器。但近年来&#xff0c;越来越多的网站开始部署针对自动化工具的检测机制&#xff0c;使得传统…...

解构 Claude Code

大多数开发者认为 AI 编码工具就是一个聊天界面。你输入&#xff0c;它回复。你复制代码。你继续前进。 Claude Code 完全不同。 1、传统方式 vs Claude Code 方式 想象雇佣一位聪明的开发者&#xff0c;他他* 每次关闭对话就忘记一切 不知道自己在什么项目除非你每次都描述…...

Win11虚拟机密码重置保姆教程:VirtualBox+系统备份双保险

Win11虚拟机密码重置与系统防护全指南&#xff1a;VirtualBox实战策略 在数字化工作环境中&#xff0c;虚拟机已成为隔离测试环境、保障系统安全的标配工具。当我们因各种原因遗忘Windows 11虚拟机密码时&#xff0c;传统物理机的解决方案往往无法直接套用。本文将深入探讨基于…...

像素幻梦快速上手指南:3步完成16-bit风格图像生成与内存流导出

像素幻梦快速上手指南&#xff1a;3步完成16-bit风格图像生成与内存流导出 1. 认识像素幻梦创意工坊 像素幻梦创意工坊&#xff08;Pixel Dream Workshop&#xff09;是一款基于FLUX.1-dev扩散模型构建的像素艺术生成工具。它采用明亮的16-bit像素风格界面设计&#xff0c;为…...

Legacy iOS Kit终极指南:让旧款iPhone/iPad重获新生的完整方案

Legacy iOS Kit终极指南&#xff1a;让旧款iPhone/iPad重获新生的完整方案 【免费下载链接】Legacy-iOS-Kit An all-in-one tool to downgrade/restore, save SHSH blobs, and jailbreak legacy iOS devices 项目地址: https://gitcode.com/gh_mirrors/le/Legacy-iOS-Kit …...

华为eNSP实战:三层交换机互连配置全流程(附常见错误排查)

华为eNSP实战&#xff1a;三层交换机互连配置全流程&#xff08;附常见错误排查&#xff09; 在企业网络架构中&#xff0c;三层交换机扮演着至关重要的角色&#xff0c;它不仅能实现二层交换功能&#xff0c;还能进行三层路由转发。华为eNSP作为一款优秀的网络仿真平台&#x…...

Python金融计算提速迫在眉睫!(仅剩3类未公开的底层优化手段,第3种已被高盛2023年专利覆盖)

第一章&#xff1a;Python金融计算提速迫在眉睫&#xff01;&#xff08;仅剩3类未公开的底层优化手段&#xff0c;第3种已被高盛2023年专利覆盖&#xff09;高频回测、实时风险敞口计算与蒙特卡洛期权定价正面临Python原生执行效率的严峻瓶颈。当单次万标的风险因子矩阵运算耗…...

想为小说配图?试试圣女司幼幽-造相Z-Turbo,我的真实使用体验

想为小说配图&#xff1f;试试圣女司幼幽-造相Z-Turbo&#xff0c;我的真实使用体验 1. 为什么我需要这个AI绘画工具 作为一名网络小说作者&#xff0c;我经常遇到一个难题&#xff1a;如何在社交媒体上为我的小说章节配上吸引人的插图。找画师定制价格昂贵&#xff0c;自己学…...

绝区零一条龙自动化工具:从机械操作到智能游戏的进化指南

绝区零一条龙自动化工具&#xff1a;从机械操作到智能游戏的进化指南 【免费下载链接】ZenlessZoneZero-OneDragon 绝区零 一条龙 | 全自动 | 自动闪避 | 自动每日 | 自动空洞 | 支持手柄 项目地址: https://gitcode.com/gh_mirrors/ze/ZenlessZoneZero-OneDragon 当你第…...