「树形结构」基于 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重要参数 …...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
