「树形结构」基于 Antd 实现一个动态增加子节点+可拖拽的树
效果
如图所示



实现
import { createRoot } from 'react-dom/client';
import React, { useState } from 'react';
import { Tree, Input, Button } from 'antd';
import { PlusOutlined } from '@ant-design/icons';const { TreeNode } = Tree;
const { Search } = Input;const initialData = [{title: 'Root Node',key: '0',children: [{title: ' Node',key: '1',}],},
];const DynamicTree = () => {const [treeData, setTreeData] = useState(initialData);const [expandedKeys, setExpandedKeys] = useState(['0']);const [autoExpandParent, setAutoExpandParent] = useState(true);const onExpand = (expandedKeys) => {setExpandedKeys(expandedKeys);setAutoExpandParent(false);};const addNode = (key, title = 'New Node') => {const addNodeRecursively = (nodes) => {return nodes.map((node) => {if (node.key === key) {const newNode = {title,key: `${key}-${node.children ? node.children.length : 0}`,children: [],};return {...node,children: [...node.children, newNode],};} else if (node.children) {return {...node,children: addNodeRecursively(node.children),};}return node;});};setTreeData((prevData) => addNodeRecursively(prevData));setExpandedKeys((prevKeys) => [...prevKeys, key]);};const renderTreeNodes = (data) =>data.map((item) => (<TreeNode title={item.title} key={item.key} dataRef={item}>{item.children ? renderTreeNodes(item.children) : null}<TreeNodetitle={<Buttontype="dashed"size="small"onClick={() => addNode(item.key)}icon={<PlusOutlined />}>Add Child</Button>}key={`${item.key}-add`}/></TreeNode>));return (<div><TreeshowIcononExpand={onExpand}expandedKeys={expandedKeys}autoExpandParent={autoExpandParent}>{renderTreeNodes(treeData)}</Tree></div>);
};export default DynamicTree;const ComponentDemo = DynamicTree;createRoot(mountNode).render(<ComponentDemo />);
进一步增强实现
同层级可以拖拽
增加节点的节点始终放在最后且可以增加同级节点
而且只有末级可以增加

import { createRoot } from 'react-dom/client';
import React, { useState } from 'react';
import { Tree, Button } from 'antd';
import { PlusOutlined } from '@ant-design/icons';const { TreeNode } = Tree;const initialData = [{title: 'Root Node',key: '0',children: [],},
];const DynamicTree = () => {const [treeData, setTreeData] = useState(initialData);const [expandedKeys, setExpandedKeys] = useState(['0']);const [autoExpandParent, setAutoExpandParent] = useState(true);const onExpand = (expandedKeys) => {setExpandedKeys(expandedKeys);setAutoExpandParent(false);};const addNode = (key, title = 'New Node') => {const addNodeRecursively = (nodes) => {return nodes.map((node) => {if (node.key === key) {const newNode = {title:`${title}-${key}-${node.children ? node.children.length : 0}`,key: `${key}-${node.children ? node.children.length : 0}`,children: [],};return {...node,children: [...node.children, newNode],};} else if (node.children) {return {...node,children: addNodeRecursively(node.children),};}return node;});};setTreeData((prevData) => addNodeRecursively(prevData));setExpandedKeys((prevKeys) => [...prevKeys, key]);};const renderTreeNodes = (data, level = 0) =>data.map((item) => (<TreeNode title={item.title} key={item.key} dataRef={item}>{item.children ? renderTreeNodes(item.children, level + 1) : null}{level < 1 && (<TreeNodeselectable={false}disabled={true}icon={<PlusOutlined />}title={<Buttontype="dashed"size="small"onClick={() => addNode(item.key)}icon={<PlusOutlined />}>Add Child</Button>}key={`${item.key}-add`}/>)}</TreeNode>));const onDrop = (info) => {const dropKey = info.node.key;const dragKey = info.dragNode.key;const dropPos = info.node.pos.split('-');const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);const loop = (data, key, callback) => {data.forEach((item, index, arr) => {if (item.key === key) {return callback(item, index, arr);}if (item.children) {return loop(item.children, key, callback);}});};const data = [...treeData];let dragNode;// Find dragObjectloop(data, dragKey, (item, index, arr) => {arr.splice(index, 1);dragNode = item;});if (!info.dropToGap) {// Drop on the contentloop(data, dropKey, (item) => {item.children = item.children || [];// where to insert 示例添加到头部,可以是随意位置item.children.unshift(dragNode);});} else if ((info.node.children || []).length > 0 && // Has childreninfo.node.expanded && // Is expandeddropPosition === 1 // On the bottom gap) {loop(data, dropKey, (item) => {item.children = item.children || [];// where to insert 示例添加到头部,可以是随意位置item.children.unshift(dragNode);});} else {let ar;let i;loop(data, dropKey, (item, index, arr) => {ar = arr;i = index;});if (dropPosition === -1) {ar.splice(i, 0, dragNode);} else {ar.splice(i + 1, 0, dragNode);}}setTreeData(data);};return (<div><TreedraggableonExpand={onExpand}expandedKeys={expandedKeys}autoExpandParent={autoExpandParent}onDrop={onDrop}>{renderTreeNodes(treeData)}</Tree></div>);
};export default DynamicTree;const ComponentDemo = DynamicTree;createRoot(mountNode).render(<ComponentDemo />);
相关文章:
「树形结构」基于 Antd 实现一个动态增加子节点+可拖拽的树
效果 如图所示 实现 import { createRoot } from react-dom/client; import React, { useState } from react; import { Tree, Input, Button } from antd; import { PlusOutlined } from ant-design/icons;const { TreeNode } Tree; const { Search } Input;const ini…...
ubuntu那些ppa源在哪
Ubuntu中的 PPA 终极指南 - UBUNTU粉丝之家 什么是PPA PPA 代表个人包存档。 PPA 允许应用程序开发人员和 Linux 用户创建自己的存储库来分发软件。 使用 PPA,您可以轻松获取较新的软件版本或官方 Ubuntu 存储库无法提供的软件。 为什么使用PPA? 正如…...
20240724-然后用idea创建一个Java项目/配置maven环境/本地仓储配置
1.创建一个java项目 (1)点击页面的create project,然后next (2)不勾选,继续next (3)选择新项目名称,新项目路径,然后Finsh,在新打开的页面选择…...
PaddleOCR-PP-OCRv4推理详解及部署实现(下)
目录 前言1. 检测模型1.1 预处理1.2 后处理1.3 推理 2. 方向分类器模型2.1 预处理2.2 后处理2.3 推理 3. 识别模型3.1 预处理3.2 后处理3.3 推理 4. PP-OCRv4部署4.1 源码下载4.2 环境配置4.2.1 配置CMakeLists.txt4.2.2 配置Makefile 4.3 ONNX导出4.4 engine生成4.4.1 检测模型…...
【Golang 面试基础题】每日 5 题(二)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/UWz06 📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏…...
状态模式与订单状态机的实现
状态模式 状态模式(State Design Pattern)是一种行为设计模式,用于在对象的内部状态改变时改变其行为。这种模式可以将状态的变化封装在状态对象中,使得对象在状态变化时不会影响到其他代码,提升了代码的灵活性和可维…...
【MSP430】MSP430是什么?与STM32对比哪个性能更佳?
一、MSP430是什么? MSP430F5529LP是一款由德州仪器(TI)推出的16位微控制器单元(MCU)开发板,具有USB功能,内存配置为128KB闪存和8KB RAM,工作频率高达25MHz。 这款MCU以其高性能和多…...
Win11 操作(四)g502鼠标连接电脑不亮灯无反应
罗技鼠标连接电脑不亮灯无反应 前言 罗技技术💩中💩,贴吧技术神中神! 最近买了一个g502,结果买回来直接插上电脑连灯都不亮,问了一下客服。客服简单的让我换接口,又是下载ghub之类的…...
自定义QDialog使用详解
自定义QDialog使用详解 一、创建 QDialog 对象二、QDialog设置布局三、QDialog控制模态行为3.1 模态和非模态区别3.2 QDialog的模态使用四、使用 QDialogButtonBox五、处理对话框的结果六、使用 QDialog 的信号和槽QDialog是Qt框架中用于创建对话框窗口的基本类。对话框窗口通常…...
Pytorch使用教学2-Tensor的维度
在PyTorch使用的过程中,维度转换一定少不了。而PyTorch中有多种维度形变的方法,我们该在什么场景下使用什么方法呢? 本小节我们使用的张量如下: # 一维向量 t1 torch.tensor((1, 2)) # 二维向量 t2 torch.tensor([[1, 2, 3], …...
Interesting bug caused by getattr
题意:由 getattr 引起的有趣的 bug 问题背景: I try to train 8 CNN models with the same structures simultaneously. After training a model on a batch, I need to synchronize the weights of the feature extraction layers in other 7 models. …...
获取后端返回的图形验证码
如果后端返回的直接就是一个图形,有以下几种方式展示 一、直接在img标签里面的src里面调用接口 <img :src"dialogSrc" class"photo" alt"验证码图片" click"changeDialog">let orgUrl "/api/captcha" …...
奇怪的Excel单元格字体颜色格式
使用VBA代码修改单元格全部字符字体颜色是个很简单的任务,例如设置A1单元格字体颜色为红色。 Range("A1").Font.Color RGB(255, 0, 0)有时需要修改部分字符的颜色,如下图所示,将红色字符字体颜色修改为蓝色。代码将会稍许复杂&am…...
浅谈芯片验证中的仿真运行之 timescale (五)提防陷阱
一 仿真单位 timeunit 我们知道,当我们的代码中写清楚延时语句时,若不指定时间单位,则使用此单位; 例如: `timescale 1ns/1ps 则 #15 语句表示delay15ns; 例:如下代码,module a 的timescale是1ns/1ps, module b 是1ps/1ps; module b中的clk,频率是由输入参…...
uniapp 重置表单数据
场景 例如有数据如下 data(){return {queryForm:{value1:undefined,}} } 点击重置时候想重置form的数据, 操作 Object.assign(this.$data.queryForm, this.$options.data().queryForm); 就可以重置数据...
自学YOLO前置知识
YOLO前置知识 学习YOLO(You Only Look Once)之前,掌握一些前置知识会帮助你更好地理解和应用该技术。以下是一些推荐的前置知识领域: 计算机视觉基础: 图像处理:了解图像的基本处理技术,如滤波…...
Ubuntu18.04 编译报错: Could NOT find JNI
一、问题描述 Ubuntu18.04 编译报错 OpenCV 时,出现以下错误: Could NOT find JNI (missing: JAVA_INCLUDE_PATH JAVA_INCLUDE_PATH2 JAVA_AWT_INCLUDE_PATH)二、解决方法 先执行以下指令, export JAVA_HOME/usr/lib/jvm/java-8-openjdk-am…...
SQL labs-SQL注入(五,使用sqlmap进行cookie注入)
本文仅作为学习参考使用,本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 引言: Cookie 是一些数据, 存储于你电脑上的文本文件中。当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息。Cookie…...
C语言——内存管理
目录 前言 一、内存分类 1. 栈区(Stack) 2. 堆区(Heap) 3. 数据段(Data Segment) 4. 代码段(Code Segment) 二、内存分配方式 1、静态内存分配 2、栈内分配 3、动态内存分配 &#x…...
Unity UGUI 之 Image和Rawimage
本文仅作学习笔记与交流,不作任何商业用途 本文包括但不限于unity官方手册,唐老狮,麦扣教程知识,引用会标记,如有不足还请斧正 1.Image是什么 Unity - 手册:图像 精灵格式是什么? 1.2重要参数 …...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...
相关类相关的可视化图像总结
目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系,可直观判断线性相关、非线性相关或无相关关系,点的分布密…...
【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...
【java面试】微服务篇
【java面试】微服务篇 一、总体框架二、Springcloud(一)Springcloud五大组件(二)服务注册和发现1、Eureka2、Nacos (三)负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...
