react_flow自定義節點、邊——使用darg布局樹狀結構

文章目錄

    • ?前言
    • ?引入react-flow
    • ?自定義節點nodeType
    • ?自定義邊edgeType
    • ?添加節點
    • ?inscode代碼塊
    • ?結束

?前言

大家好,我是yma16,本文分享 前端 ——react_flow自定義節點、邊——使用darg布局樹狀結構。
自定義效果
可以自定義節點、邊、線條流動
custom-flow

React Flow 簡介

React Flow 是一個用于構建交互式節點和基于圖的編輯器的開源 React 庫。它專為可視化復雜工作流、流程圖、狀態機或依賴關系而設計,提供高度可定制化的節點、連線(edges)和交互功能。

node系列往期文章
node_windows環境變量配置
node_npm發布包
linux_配置node
node_nvm安裝配置
node筆記_http服務搭建(渲染html、json)
node筆記_讀文件
node筆記_寫文件
node筆記_連接mysql實現crud
node筆記_formidable實現前后端聯調的文件上傳
node筆記_koa框架介紹
node_koa路由
node_生成目錄
node_讀寫excel
node筆記_讀取目錄的文件
node筆記——調用免費qq的smtp發送html格式郵箱
node實戰——搭建帶swagger接口文檔的后端koa項目(node后端就業儲備知識)
node實戰——后端koa結合jwt連接mysql實現權限登錄(node后端就業儲備知識)
node實戰——koa給郵件發送驗證碼并緩存到redis服務(node后端儲備知識)

koa系列項目文章
前端vite+vue3結合后端node+koa——實現代碼模板展示平臺(支持模糊搜索+分頁查詢)
node+vue3+mysql前后分離開發范式——實現對數據庫表的增刪改查
node+vue3+mysql前后分離開發范式——實現視頻文件上傳并渲染

koa-vue性能監控到封裝sdk系列文章
性能監控系統搭建——node_koa實現性能監控數據上報(第一章)
性能監控系統搭建——vue3實現性能監控數據展示(第二章)
性能監控計算——封裝帶性能計算并上報的npm包(第三章)
canvas系列文章
web canvas系列——快速入門上手繪制二維空間點、線、面
webgl canvas系列——快速加背景、摳圖、加水印并下載圖片
webgl canvas系列——animation中基本旋轉、平移、縮放(模擬冒泡排序過程)
前端vue系列文章
vue3 + fastapi 實現選擇目錄所有文件自定義上傳到服務器
前端vue2、vue3去掉url路由“ # ”號——nginx配置
csdn新星計劃vue3+ts+antd賽道——利用inscode搭建vue3(ts)+antd前端模板
認識vite_vue3 初始化項目到打包
python_selenuim獲取csdn新星賽道選手所在城市用echarts地圖顯示
讓大模型分析csdn文章質量 —— 提取csdn博客評論在文心一言分析評論區內容
前端vue3——html2canvas給網站截圖生成宣傳海報
前端——html拖拽原理
前端 富文本編輯器原理——從javascript、html、css開始入門
前端老古董execCommand——操作 選中文本 樣式
前端如何在30秒內實現吸管拾色器?
前端——原生Selection api操作選中文本 樣式、取消樣式(解決標簽的無限嵌套問題)
前端 ——xml轉json json轉xml 實現 mjml 郵件內容轉json,json轉mjml
前端 ——youtube、tiktok視頻封面獲取并使用canvas合并封面和自定義播放按鈕生成圖片
前端gmail郵件加載動態樣式——動態評分交互郵件可提交api

?引入react-flow

安裝@xyflow/react

pnpm add @xyflow/react

基礎使用

import React from 'react';
import { ReactFlow } from '@xyflow/react';import '@xyflow/react/dist/style.css';const initialNodes = [{ id: '1', position: { x: 0, y: 0 }, data: { label: '1' } },{ id: '2', position: { x: 0, y: 100 }, data: { label: '2' } },
];
const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];export default function App() {return (<div style={{ width: '100vw', height: '100vh' }}><ReactFlow nodes={initialNodes} edges={initialEdges} /></div>);
}

?自定義節點nodeType

定義一個BaseNode ,可以引用flow的handle展示線條的連接點

import { Handle, Position, NodeToolbar } from '@xyflow/react';
import React, { useEffect } from 'react';
import './style.scss';const BaseNode = (props: any) => {const { data } = props;useEffect(() => {console.log('props', props);}, [props]);return (<div className="base-node"><NodeToolbar isVisible={data.toolbarVisible} position={Position.Top}><button>toolbar 按鈕</button></NodeToolbar><div style={{ padding: '10px 20px' }}>{data.label}</div>{/* {data.customDataType !== 'start' ? <Handle type="source" position={Position.Top} /> : ''} */}{data.customDataType !== 'end' ? <Handle type="source" position={Position.Bottom} /> : ""}{data.customDataType !== 'start' ? <Handle type="target" position={Position.Top} /> : ""}</div >);
};export default BaseNode;

flow組件nodeType引入BaseNode

    const nodeTypes = useMemo(() => {return { textUpdater: TextUpdaterNode, AddNode: AddNode, baseNode: BaseNode };}, [TextUpdaterNode, AddNode, BaseNode]);

節點引用 type: ‘baseNode’

// 初始節點
export const initialNodes = [{id: 'start_id',position: { x: 0, y: 0 },data: { label: `開始節點_${new Date().Format('yyyy-MM-dd hh:mm:ss')}`, customDataType: 'start' },type: 'baseNode'},{id: 'test_id',position: { x: 0, y: 0 },data: { label: `測試節點_${new Date().Format('yyyy-MM-dd hh:mm:ss')}`, customDataType: 'test' },type: 'baseNode'},{id: 'end_id',position: { x: 0, y: 0 },data: { label: `結束節點_${new Date().Format('yyyy-MM-dd hh:mm:ss')}`, customDataType: 'end' },type: 'baseNode'}
];

?自定義邊edgeType

自定義邊——添加按鈕

import {BaseEdge,EdgeLabelRenderer,getStraightPath,getSmoothStepPath,getSimpleBezierPath,Position,useReactFlow,
} from '@xyflow/react';import './style.scss'
import React, { useState } from 'react';export default function CustomAddEdge(props: any) {const { id, sourceX, sourceY, targetX, targetY, data } = props;console.log('CustomAddEdge props', props);console.log('CustomAddEdge props data', data);const [isShowAddPanel, setIsShowAddPanel] = useState(false);const [isSelectEdge, setIsSelectEdge] = useState(false);const [path,] = getSimpleBezierPath({sourceX: sourceX,sourceY: sourceY,// sourcePosition: Position.Top,targetX: targetX,targetY: targetY,// targetPosition: Position.Bottom,});const [edgePath, labelX, labelY] = getStraightPath({sourceX,sourceY,targetX,targetY,});return (<><BaseEdge id={id} path={path} /><circle r="10" fill="#ff0073"><animateMotion dur="2s" repeatCount="indefinite" path={edgePath} /></circle><EdgeLabelRenderer><buttonstyle={{position: 'absolute',transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,pointerEvents: 'all',borderRadius: '50px',cursor: 'pointer',}}className="add-button"onClick={() => {setIsSelectEdge(true)console.log('add button clicked', props);setIsShowAddPanel(!isShowAddPanel);}}>+<div style={{display: isShowAddPanel ? 'block' : 'none',}} className='add-button-edge-panel-container'><div ><button onClick={() => {console.log('添加普通節點');data?.onAddBaseNode?.({curEdgeId: id});}} className='add-button-edge-panel'>添加普通節點</button></div><div><br></br></div><div ><button onClick={() => {console.log('添加分支節點 left');data?.onAddBranchNode?.({curEdgeId: id,direction: 'left'});}} className='add-button-edge-panel'>添加分支 保留左邊</button></div><div><br></br></div><div ><button onClick={() => {console.log('添加分支節點 right');data?.onAddBranchNode?.({curEdgeId: id,direction: 'right'});}} className='add-button-edge-panel'>添加分支 保留右邊</button></div></div></button></EdgeLabelRenderer></>);
}

?添加節點

基礎節點

// 添加基礎節點
export const addBaseNode = (config: { curEdgeId: string; nodes: any[]; edges: any[] }) => {const { curEdgeId, nodes, edges } = config;console.log('addBaseNode curEdgeId', curEdgeId);// 當前邊的節點const curEdge = edges.find(edge => edge.id === curEdgeId);if (!curEdge) {console.error('Edge not found for id:', curEdgeId);return { nodes, edges };}// 創建新的節點 基礎節點const virtualNode = {id: customGenUuid(),position: { x: 0, y: 0 },data: { label: `普通節點_${new Date().Format('yyyy-MM-dd hh:mm:ss')}`, customDataType: 'test' },type: 'baseNode'};// 新節點const newNodes: any[] = [];// 遍歷節點添加  按順序加入nodes.forEach(node => {if (node.id === curEdge.source) {// 在當前邊的源節點后面添加新節點newNodes.push(virtualNode);}newNodes.push(node);});// 添加新邊const newEdges: any[] = [];edges.forEach(edge => {// 如果是當前邊,則添加新邊  source和target 中間添加一個節點 補充一條邊if (edge.id === curEdgeId) {// 在當前邊后面添加新邊newEdges.push({id: customGenUuid(),source: curEdge.source,// 鏈接當前節點target: virtualNode.id,type: 'customAddEdge',markerEnd: {type: MarkerType.Arrow}});// 在當前邊后面添加新邊newEdges.push({id: customGenUuid(),source: virtualNode.id,// 鏈接當前節點target: curEdge.target,type: 'customAddEdge',markerEnd: {type: MarkerType.Arrow}});} else {// 其他邊不變newEdges.push(edge);}});return {newNodes: newNodes,newEdges: newEdges};
};

添加分支節點

// 添加分支節點  默認添加左分支
export const addBranchNode = (config: { curEdgeId: string; nodes: any[]; edges: any[]; direction: string }) => {const { curEdgeId, nodes, edges, direction } = config;console.log('addBaseNode curEdgeId', curEdgeId);// 當前邊的節點const curEdge = edges.find(edge => edge.id === curEdgeId);if (!curEdge) {console.error('Edge not found for id:', curEdgeId);return { nodes, edges };}// 創建新的節點 基礎節點const virtualLeftNode = {id: customGenUuid(),position: { x: 0, y: 0 },// 左邊分支 節點data: { label: `分支節點_${new Date().Format('yyyy-MM-dd hh:mm:ss')}`, customDataType: 'test', branchDirection: 'left' },type: 'baseNode'};// 右邊分支節點const virtualRightNode = {id: customGenUuid(),position: { x: 0, y: 0 },// 左邊分支 節點data: { label: `分支節點_${new Date().Format('yyyy-MM-dd hh:mm:ss')}`, customDataType: 'test', branchDirection: 'right' },type: 'baseNode'};// 新節點const newNodes: any[] = [];// 遍歷節點添加  按順序加入nodes.forEach(node => {if (node.id === curEdge.source) {// 在當前邊的源節點后面添加新節點  先添加左邊在添加右邊的節點if (direction === 'left') {newNodes.push(virtualLeftNode);newNodes.push(virtualRightNode);} else {// 右邊分支newNodes.push(virtualRightNode);newNodes.push(virtualLeftNode);}}newNodes.push(node);});// 添加新邊const newEdges: any[] = [];edges.forEach(edge => {// 如果是當前邊,則添加新邊  source和target 中間添加一個節點 補充一條邊if (edge.id === curEdgeId) {// 在當前邊后面添加新邊newEdges.push({id: customGenUuid(),source: curEdge.source,// 鏈接當前節點target: direction === 'left' ? virtualLeftNode.id : virtualRightNode.id,data: {branchDirection: 'right'},type: 'customAddEdge',markerEnd: {type: MarkerType.Arrow}});// 在當前邊后面添加新邊newEdges.push({id: customGenUuid(),source: direction === 'left' ? virtualLeftNode.id : virtualRightNode.id,// 鏈接當前節點target: curEdge.target,data: {branchDirection: 'right'},type: 'customAddEdge',markerEnd: {type: MarkerType.Arrow}});// 添加右側分支邊newEdges.push({id: customGenUuid(),source: curEdge.source,// 鏈接當前節點target: direction === 'left' ? virtualRightNode.id : virtualLeftNode.id,type: 'customAddEdge',data: {branchDirection: 'right'},markerEnd: {type: MarkerType.Arrow}});} else {// 其他邊不變newEdges.push(edge);}});console.log('addBranchNode newNodes', {newNodes: newNodes,newEdges: newEdges});return {newNodes: newNodes,newEdges: newEdges};
};

?inscode代碼塊

效果演示

react_flow特點

節點與連線:支持自定義節點(矩形、圓形等)和動態連線(貝塞爾曲線、直線等)。
交互功能:拖拽節點、縮放畫布、選擇多個元素、鍵盤快捷鍵支持。
狀態管理:與外部狀態庫(如 Redux、Zustand)無縫集成。
插件系統:內置背景網格、迷你地圖、節點工具欄等插件。
性能優化:僅渲染可見區域的節點,適合大規模數據場景。
react-flow存在的問題
React Flow在處理大規模節點和連線時可能出現性能瓶頸,尤其是當畫布包含數百個節點時,渲染和交互可能變得遲緩。動態添加或刪除節點時的重繪操作可能消耗較多資源。

?結束

本文分享到這結束,如有錯誤或者不足之處歡迎指出!

scene

👍 點贊,是我創作的動力!

?? 收藏,是我努力的方向!

?? 評論,是我進步的財富!

💖 最后,感謝你的閱讀!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87231.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87231.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87231.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

word表格批量轉excel,提取表格數據到excel

本文將帶你一步步實現一個將 Word 中的表格內容批量提取并轉換為 Excel 文件的自動化工具&#xff0c;適用于需要手動復制粘貼數據到excel的場景 假設我們有這樣的表格在word中&#xff0c;圖片世放在excel中便于截圖&#xff0c;現在需要將表格中有顏色的數據提取到對應的exce…

day2課程

1.添加pinia到Vue項目 2.counter基礎使用 3.getters和異步action 4.storeToRefs和調試 5.項目初始化和git管理 6.別名路徑聯想設置 7.elementsPlus自動按需導入配置 這個項目使用的是按需引入 1.安裝包管理器 npm install element-plus --save 2.按需引入 npm install -D unp…

Vue3 + TypeScript + Element Plus 設置表格行背景顏色

技術要點&#xff1a; 1、使用 :row-class-name"setRowClassName" 設置表格行類名 2、不能同時使用 stripe 3、設置行類名的樣式 應用效果&#xff1a; 同時使用 stripe 出來的效果&#xff1a; 參考代碼&#xff1a; ReagentTable.vue <script setup lang&…

山東大學 軟件項目管理知識點總結

軟件項目管理背誦總結 將老師所發ppt的知識點整理&#xff0c;方便查閱與背誦。 文章目錄 軟件項目管理背誦總結1. 概述1.1 什么是項目&#xff1f;1.2 項目有那些特征&#xff1f;1.3 項目于日常工作有什么區別&#xff1f;1.4 如何衡量一個項目是否成功&#xff1f;1.5 軟件項…

css基礎筆記簡潔版1

&#x1f4d8; CSS 基礎筆記 1 一、CSS 簡介 CSS&#xff08;層疊樣式表&#xff09;用于為網頁添加樣式&#xff0c;實現結構與樣式分離&#xff0c;能夠控制顏色、字體、布局、位置、動畫等視覺效果。 二、基本語法 選擇器 {屬性1: 值1;屬性2: 值2; }說明&#xff1a; 選…

reactor模型學習

學習鏈接 狂野架構師第四期netty視頻 - B站視頻 狂野架構師訓練營6期 - B站視頻 Netty學習example示例&#xff08;含官方示例代碼&#xff09; LG-Netty學習 【硬核】肝了一月的Netty知識點 - 啟動過程寫的很詳細 Reactor模型講解 一文搞懂Reactor模型與實現 高性能網絡編…

應用探析|千眼狼高速攝像機、sCMOS相機、DIC測量、PIV測量在光學領域的應用

2025&#xff0c;長春&#xff0c;中國光學學會學術大會。中科視界攜千眼狼品牌四大科學儀器高速攝像機、sCMOS科學相機、DIC應變測量系統、PIV流場測量系統亮相&#xff0c;在光學領域多個細分研究方向承載科學實驗的感知與測量任務。 1先進制造技術及其應用 激光切割、激光焊…

Kafka 4.0.0集群部署

Kafka 4.0.0集群部署 1.1 關閉防火墻和 selinux 關閉防火墻 systemctl stop firewalld.service systemctl disable firewalld.service關閉selinux setenforce 0 #&#xff08;臨時生效&#xff09; sed -i s/^SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config #&…

探秘卷積神經網絡(CNN):從原理到實戰的深度解析

在圖像識別、視頻處理等領域&#xff0c;卷積神經網絡&#xff08;Convolutional Neural Network&#xff0c;簡稱 CNN&#xff09;如同一位 “超級偵探”&#xff0c;能夠精準捕捉圖像中的關鍵信息&#xff0c;實現對目標的快速識別與分析。從醫療影像診斷到自動駕駛中的路況感…

vue3導入xlsx表格處理數據進行渲染

下載插件 npm install -S xlsx import * as XLSX from "xlsx"; // Vue3 版本 <el-upload class"upload-demo"accept".xlsx":http-request"channel":show-file-list"false":limit"1"><el-button type&qu…

生成模型_條件編碼器

條件編碼器可以采用不同的網絡結構&#xff0c;UNet 是其中非常常見的一種&#xff0c;尤其在 Diffusion 和圖像生成任務中用得最多。 &#x1f9e0; 什么是“條件編碼器”&#xff1f; 在 **條件生成模型&#xff08;Conditional GAN / Diffusion&#xff09;**中&#xff0c…

@Scheduled, @PostConstruct, @PreDestroy, @Async, @OnApplicationEvent

注解名稱模塊功能引入年份版本是否推薦使用PostConstructjavax.annotation (Java EE) / spring-beansBean 初始化完成后執行的方法2006Java EE 5 / Spring 2.0?? 推薦PreDestroyjavax.annotation (Java EE) / spring-beansBean 銷毀前執行的方法2006Java EE 5 / Spring 2.0?…

小程序請求加載提示防閃爍機制詳解

目錄 一、問題背景&#xff1a;閃爍現象的產生 二、完整解決方案代碼 三、核心防閃爍機制解析 1. 請求計數器&#xff08;requestCount&#xff09; 2. 延遲隱藏定時器&#xff08;關鍵創新&#xff09; 3. 100ms緩沖期的重要意義 四、關鍵場景對比分析 場景1&#xff…

linux防火墻講解

目錄 安全管理 一、SELinux安全上下文 1、SELinux 簡介 2、基礎操作命令 1. 查看SELinux狀態 2. 切換工作模式* 3、安全上下文&#xff08;Security Context&#xff09; 1. 查看上下文* 2. 修改上下文 chcon命令 semanage 命令 4、SELinux布爾值&#xff08;Boole…

巧用 Python:將 A3 作業 PDF 輕松轉為 A4 可打印格式

在孩子的學習過程中&#xff0c;我們常常會遇到這樣的困擾&#xff1a;學校老師發的作業是以 A3 格式的 PDF 文件呈現的&#xff0c;然而家里的打印機卻只支持 A4 打印。這時候&#xff0c;要是能有一個簡單的方法把 A3 的 PDF 轉換為 A4 可打印的格式就好了。別擔心&#xff0…

Transformer 核心概念轉化為夏日生活類比

以下是把 Transformer 核心概念轉化為「夏日生活類比」&#xff0c;不用看代碼也能秒懂&#xff0c;搭配冰鎮西瓜式記憶法&#xff1a; 一、Transformer 夏日冷飲制作流水線 編碼器&#xff08;Encoder&#xff09;&#xff1a;相當于「食材處理間」 把輸入&#xff08;比如…

【Linux基礎知識系列】第二十九篇-基本的網絡命令(ping, traceroute, netstat)

在Linux系統中&#xff0c;網絡診斷是系統管理員和用戶日常工作中不可或缺的一部分。無論是排查網絡連接問題、檢查網絡延遲&#xff0c;還是監控網絡狀態&#xff0c;掌握一些基本的網絡命令至關重要。本文將詳細介紹ping、traceroute和netstat這三種常用的網絡命令&#xff0…

javaee初階-多線程

1.什么是線程 1.1 進程 要了解線程我們首先需要了解什么是進程&#xff1f; 運行的程序在操作系統中以進程的方式運行&#xff0c;比如說電腦打開不同的軟件&#xff0c;軟件就是不同的進程 1.1.1進程的組織方式 通過雙向鏈表 創建進程就是在雙向鏈表上添加PCB 銷毀一個進…

N數據分析pandas基礎.py

前言&#xff1a;在數據分析領域&#xff0c;Python 的 Pandas 庫堪稱得力助手。它不僅擁有高效的數據處理能力&#xff0c;還能與 NumPy 完美配合——后者強大的數值計算功能為 Pandas 提供了堅實的技術基礎。 目錄 Pandas數據分析實戰&#xff1a;解鎖數據處理的高效之道 數…

衛星通信鏈路預算之二:帶寬和功帶平衡

在上一個章節衛星通信鏈路預算之一&#xff1a;信噪比分配 中&#xff0c;我們介紹了衛星通信鏈路中最核心的概念&#xff1a;信噪比分配&#xff0c;并給出了衛星通信鏈路總信噪比的計算公式。 本篇文章&#xff0c;我們將介紹衛星通信鏈路中的另外一個基本概念&#xff1a;帶…