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

前端-Vue3递归组件自定义Tree

需求

PS:写在前面,需求想要一个Tree 形结构展示当前的组织机构,最末层节点可以选择,层级明确。第一选择网上npm官网或者github 找找成型的东西

  1. element-ui Tree 没有组织结构线
  2. js-tree 好看,但是适配Vue3 有点费劲,Vue2 倒是还好
  3. echart Tree 感觉有点类似xmind,不是想要的效果
    最好的就是在element-ui Tree 加上组织连线这就是最完美的效果。

方案选择

  1. 引入element-ui Tree,二次封装增加连线样式(实现简单,效果明显,效率高)。
  2. 自己写一个Tree ※
    但是我选第二个,能了解Tree 组件实现原理,自己想要啥样的就写啥样的,哈哈哈哈。

Vue 递归组件

  1. 递归:自己调用自己,什么时候终止(没有子集就终止)
// TreeWithSwitch 就是子组件
<template><div class="TreeWithSwitch" v-for="item in dataList" :key="item.code">// 本级标题以及选择框展示<div class="tree_content"><span>{{ item.label }}</span><van-switch size="18px" v-if="item.isLeaf" v-model="item.checked" /></div>// 递归 判断是否有子集<div class="node_children"><tree-with-switch :data-list="item.children" v-if="item.children.length" /></div></div>
</template>

在这里插入图片描述

  1. 增加样式展示层级
.TreeWithSwitch {line-height: 30px;padding-left: 20px;margin-left: 25px;.tree_content {display: flex;align-items: center;justify-content: space-between;padding-right: 10px;height: 35px;font-size: 13px;white-space: nowrap;outline: 0;position: relative;}
}

在这里插入图片描述

  1. 通过伪类增加当前连接线样式
.TreeWithSwitch {position: relative;line-height: 30px;padding-left: 20px;margin-left: 25px;.tree_content {display: flex;align-items: center;justify-content: space-between;padding-right: 10px;height: 35px;font-size: 13px;white-space: nowrap;outline: 0;position: relative;&::before {position: absolute;top: 50%;left: -19px;display: block;width: 17px;border-top: 1px dashed #43484b;content: '';}&::after {content: '';border-left: 1px dashed #43484b;width: 1px;height: 30px;position: absolute;left: -21px;top: -11px;}}
}

在这里插入图片描述

  1. 可以看到很多空缺的部分,上一次绘制的是在每个层级的:before :after 绘制的横线和竖线,分析缺少的部分正是当前节点子集的这部分连接线
    在这里插入图片描述
.TreeWithSwitch {position: relative;line-height: 30px;padding-left: 20px;margin-left: 25px;&:last-child {.node_children {&::after {display: none;}}}.node_children {position: relative;&::after {content: '';border-left: 1px dashed #43484b;position: absolute;height: 100%;left: -21px;top: -11px;}}.tree_content {display: flex;align-items: center;justify-content: space-between;padding-right: 10px;height: 35px;font-size: 13px;white-space: nowrap;outline: 0;position: relative;&::before {position: absolute;top: 50%;left: -19px;display: block;width: 17px;border-top: 1px dashed #43484b;content: '';}&::after {content: '';border-left: 1px dashed #43484b;width: 1px;height: 30px;position: absolute;left: -21px;top: -11px;}}
}

在这里插入图片描述
5. 但是可以发现所有的Tree的最外层是没有margin-left:20px 的,也没有上图的多余的部分,那怎么办呢,找了下ElementUI tree 的源码,他把第一层级拿出来了,然后才是递归组件,OK,那我们在封装一个Tree 组件

# Tree 组
<template><div class="Tree" v-for="item in dataList"><second-title :title="item.label" /><tree-with-switch v-if="item.children" :data-list="item.children" /></div>
</template><script setup lang="ts">
import type TreeItem from '@/components/public/Tree/TreeItem';
import SecondTitle from '@/components/public/appTitle/SecondTitle.vue';
import TreeWithSwitch from '@/components/public/Tree/TreeWithSwitch.vue';const props = defineProps({dataList: {type: Array<TreeItem>,required: true}
});
</script><style scoped lang="less">
.SecondTitle {margin-left: 5px;
}
</style>

在这里插入图片描述
OK,写到这里基本上样式问题已经解决了,接下来

最后一步,用你的组件的时候如果获取那些是选中的节点如何获取?

PS:子集不处理事件,无限向上抛出,最后有父级处理。

# TreeWithSwitch
<template><div class="TreeWithSwitch" v-for="item in dataList" :key="item.code"><div class="tree_content"><span>{{ item.label }}</span>// 增加选中事件<van-switch size="18px" v-if="item.isLeaf" v-model="item.checked" @change="chooseTreeItem(item)" /></div>// 子集选中事件<div class="node_children"><tree-with-switch :data-list="item.children" v-if="item.children.length" @chooseTreeItem="chooseChildrenItem"/></div></div>
</template><script setup lang="ts">
import type TreeItem from '@/components/public/Tree/TreeItem';defineProps({dataList: {type: Array<TreeItem>,required: true}
});
// 子集向上抛出事件
const emits = defineEmits(['chooseTreeItem']);
const chooseTreeItem = (item: TreeItem) => {emits('chooseTreeItem', item);
};
// 子集的子集继续向上排除(这里就是逐级传递的)
const chooseChildrenItem = (item: TreeItem) => {chooseTreeItem(item);
};
</script>

Tree 组件

<template><div class="Tree" v-for="item in dataList"><second-title :title="item.label" />// 增加绑定选中事件<tree-with-switch v-if="item.children" :data-list="item.children" @chooseTreeItem="chooseTreeItem" /></div>
</template><script setup lang="ts">
import type TreeItem from '@/components/public/Tree/TreeItem';
import SecondTitle from '@/components/public/appTitle/SecondTitle.vue';
import TreeWithSwitch from '@/components/public/Tree/TreeWithSwitch.vue';
import { ref } from 'vue';const props = defineProps({dataList: {type: Array<TreeItem>,required: true},// 定义v-model绑定的参数chooseItemList: {type: [],required: false}
});
// 保存全部选中的节点
const selectedTreeNode = ref([]);
// 值更新抛出事件
const emits = defineEmits(['update:chooseItemList']);
const chooseTreeItem = (item: TreeItem) => {// 节点是否选中,选中数组新增,取消选中数组删除if (item.checked) {selectedTreeNode.value.push(item.code);} else {let index = selectedTreeNode.value.indexOf(item.code);if (index > -1) {selectedTreeNode.value.splice(index, 1);}}// 绑定值更新emits('update:chooseItemList', selectedTreeNode.value);
};
</script>

调用组件

// :data-list Tree 的数据
// v-model:chooseItemList 选中的值
<tree :data-list="hiddenItemList" v-model:chooseItemList="chooseHiddenItemList" />

在这里插入图片描述

相关文章:

前端-Vue3递归组件自定义Tree

需求 PS&#xff1a;写在前面&#xff0c;需求想要一个Tree 形结构展示当前的组织机构&#xff0c;最末层节点可以选择&#xff0c;层级明确。第一选择网上npm官网或者github 找找成型的东西 element-ui Tree 没有组织结构线js-tree 好看&#xff0c;但是适配Vue3 有点费劲&a…...

《TCP/IP详解 卷一》第12章 TCP初步介绍

目录 12.1 引言 12.1.1 ARQ和重传 12.1.2 滑动窗口 12.1.3 变量窗口&#xff1a;流量控制和拥塞控制 12.1.4 设置重传的超时值 12.2 TCP的引入 12.2.1 TCP服务模型 12.2.2 TCP可靠性 12.3 TCP头部和封装 12.4 总结 12.1 引言 关于TCP详细内容&#xff0c;原书有5个章…...

作业1-224——P1015 [NOIP1999 普及组] 回文数

题目描述 思路 首先此题为一道高精度题&#xff0c;然后本题按照题目意思模拟即可。我们可以开两个数组来记录高精度数字&#xff0c;这样方便我们处理。判断“该数组是否回文”、“c翻转存入d再做cd”可以写成两个单独的函数。然后主程序组织一下他们即可。注意好退出循环的…...

后端知识(理解背诵)

文章目录 &#x1f37a; 来源&#x1f37a; C&#x1f37b; new 和 malloc 的区别&#xff1f;2&#x1f37b; delete 和 delete[] 的区别&#xff1f;0&#x1f37b; 内存泄漏是什么&#xff1f;如何避免&#xff1f;1 &#x1f37a; 计算机网络&#x1f37b; URL 输入后发生了…...

构造pop链

反序列化视频笔记 第一步&#xff1a;找到目标触发echo调用$flag 第二步&#xff1a;触发_invoke函数调用appeng函数$varflag.php&#xff08;把对象当成函数&#xff09; 第三步&#xff1a;给$p赋值为对象&#xff0c;即function成为对象Modifier却被当成函数调用&#xff…...

JAVA设计模式——创建型模式

JAVA设计模式——创建型模式 一、创建型模式1.单例模式&#xff08;Singleton Pattern&#xff09;1.1 饿汉式1.2 懒汉式1.3 双重检验锁(double check lock)(DCL)1.4 静态内部类1.5 枚举1.6 破坏单例的几种方式与解决方法1.6.1 反序列化1.6.2 反射 1.7 容器式单例1.8 ThreadLoc…...

队列的结构概念和实现

文章目录 一、队列的结构和概念二、队列的实现三、队列的实现函数四、队列的思维导图 一、队列的结构和概念 什么是队列&#xff1f; 队列就是只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出 如上图所示&#x…...

Linux系统上使用C语言创建线程

文章目录 一、使用C代码创建线程示例API 二、线程的相关知识2.1 线程 与 进程 的关系2.2 使用线程的理由 一、使用C代码创建线程 使用pthread_create函数创建线程。 示例 示例&#xff1a;创建一个线程&#xff0c;其作用就是打印线程ID和传入参数。 //demo1 #include <…...

pc端如何做自适应呢?

<!-- 默认html的font-size的大小是16px 1rem 16px --> <!-- 想要实现自适应的前提条件是 当浏览器的窗口发生变化的时候&#xff0c; html的font-size将会跟着发生改变 --> <!-- 实现的步骤如下 --> <!-- 1 借助flexble.js文件 --> <!-- 2 将fle…...

c语言经典测试题8

在c语言经典测试题6的第一题&#xff0c;大家是否想过可不可以将递归参数改为s呢&#xff1f;或许有的人已经试过了&#xff0c;但是发现好像不会有结果&#xff0c;其实是因为s为后置&#xff0c;先试用后加1&#xff0c;然而我们这个是在s出了函数之后才会运行加1操作&#x…...

解决GitHub无法访问的问题:手动修改hosts文件与使用SwitchHosts工具

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua&#xff0c;在这里我会分享我的知识和经验。&#x…...

ETL数据仓库的使用方式

一、ETL的过程 在 ETL 过程中&#xff0c;数据从源系统中抽取&#xff08;Extract&#xff09;&#xff0c;经过各种转换&#xff08;Transform&#xff09;操作&#xff0c;最后加载&#xff08;Load&#xff09;到目标数据仓库中。以下是 ETL 数仓流程的基本步骤&#xff1a…...

POST参数里加号+变成空格的问题处理

今天遇到个这样的问题&#xff0c;从前端传到后端的加密报文&#xff0c;里面包含了号&#xff0c;但在后端日志输出看出&#xff0c;变成空格。这个是由于经过RSA加密后引起的 解决办法&#xff1a; 1.前端转码&#xff1a;使用encodeURIComponent对参数进行转码 2.后端解码…...

【华为面试基础题】检查是否存在满足条件的数字组合

描述 给定一个正整数数组检查数组中是否存在满足规则的数组组合 规则&#xff1a; AB2C 输入描述&#xff1a; 第一行输出数组的元素个数&#xff0c;接下来一行输出所有数组元素&#xff0c;用空格隔开 输出描述&#xff1a; 如果存在满足要求的数 在同一行里依次输出 规则…...

亚信安慧AntDB数据并行加载工具的实现(一)

1.概述 数据加载速度是评判数据库性能的重要指标&#xff0c;能否提高数据加载速度&#xff0c;对文件数据进行并行解析&#xff0c;直接影响数据库运维管理效率。基于此&#xff0c;AntDB分布式数据库提供了两种数据加载方式&#xff1a; 一是类似于PostgreSQL的Copy命令&am…...

面经 | Java创建线程的三种方式

利用JUC包创建线程的三种方式&#xff1a; 通过继承Thread类创建线程类实现Runnable接口创建线程类通过Callable和Future接口创建线程 继承Thread类创建线程 class Thread1 extends Thread {Overridepublic void run() {System.out.println("启动线程1");} }实现R…...

【计算机网络】五种IO模型与IO多路转接之select

文章目录 一、五种IO模型二、非阻塞IO1.fcntl2.实现函数SetNoBlock3.轮询方式读取标准输入 三、I/O多路转接之select1.初识select2.select函数原型3.socket就绪条件4.select的特点5.select缺点6.select使用案例--只读取数据的server服务器1.err.hpp2.log.hpp3.sock.hpp4.select…...

通过一篇文章让你了解数据结构和算法的重要性

通过一篇文章让你了解数据结构和算法的重要性 前言一、 什么是数据结构&#xff1f;二、什么是算法&#xff1f;三、数据结构和算法的重要性在校园招聘的笔试中&#xff1a;在校园招聘的面试中&#xff1a;在未来的工作中&#xff1a; 四、如何学好数据结构和算法4.1 死磕代码&…...

python代码优化学习

代码优化对比&#xff1a; 优化前&#xff1a; # 登录系统 xxljob_login() start_time time.time() # 循环处理需要补数的数据 for item in authId_lists: preSettleInfoHandler(item) count 1 print("运行了第" str(count) "个") …...

C#,数值计算,求解微分方程的吉尔(Gear)四阶方法与源代码

1 微分方程 微分方程&#xff0c;是指含有未知函数及其导数的关系式。解微分方程就是找出未知函数。 微分方程是伴随着微积分学一起发展起来的。微积分学的奠基人Newton和Leibniz的著作中都处理过与微分方程有关的问题。微分方程的应用十分广泛&#xff0c;可以解决许多与导数…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…...