• 使用 React Flow 构建一个思维导图应用


    242d9ec432ebcf91c101501536bfdf6b.jpeg

    4f93d83082235977d4242b2bd3062fb0.jpeg

    思维导图是围绕共同主题或问题将思想、概念、信息或任务分组的视觉表示。思维导图应用是一种软件应用,允许您创建、可视化和组织您的思想、想法和信息作为思维导图。本文将向您展示如何实现自己的思维导图应用程序。

    在我们开始之前,我想向您展示一下我们在本教程结束时将拥有的思维导图应用程序

    66c02940210259423ed562e03e1a0017.png

    React Flow是什么?

    React Flow是一个开源工具包,用于在React应用程序中生成交互式图表、流程图和可视化。它提供了一种强大的方式来创建和管理复杂的可视化,如思维导图、网络图和组织结构图等。React Flow基于React构建,并使用现代Web技术提供统一的用户体验。

    成千上万的用户使用React Flow,从个人开源开发者到像Stripe和Typeform这样的大公司。该库已被用于数据处理工具、聊天机器人构建器、机器学习、音乐合成器和其他应用程序中。

    选择一个满足你需求的库可能会很困难,因为在不断发展的行业中有太多的选择。然而,使用React Flow、思维导图以及规划和设计你的项目可能会简化这个过程,节省你的时间和烦恼。

    尽管市场上有众多竞争对手,但React Flow作为最出色的思维导图和流程框架之一,仍然在大型项目的开发过程中持续为用户带来好处。

    在本教程中,您将学习如何使用React Flow创建一个基本的思维导图应用程序,该应用程序可用于头脑风暴、构思想法或可视化思维。

    项目设置

    让我们从搭建我们的React应用开始。通过运行以下命令在您选择的目录中搭建React:

    1. npm create vite@latest mind-mapping-app --template react
    2. cd mind-mapping-app

    Vite是一个为主要框架提供的工具,可以让您从基本模板快速启动项目。这些模板由社区维护,并针对各种框架或集成其他工具。其中一个模板可以使用类似Degit的工具来搭建您的项目。

    1. npx degit user/project my-project
    2. cd mind-mapping-app
    3. npm install
    4. npm run dev

    创建组件

    要创建一个组件,请在您的思维导图应用的src文件夹中导航并创建一个组件(component)文件夹。接下来,在组件文件夹中创建一个新文件, node.jsx 。

    集成React Flow

    将React Flow集成到您的Vite React项目中,请按照以下步骤进行操作:

    首先,请确保您已经安装了React Flow。如果还没有安装,请运行以下命令:

    npm install react-flow-renderer

    接下来,导航到 node.jsx 目录并粘贴以下代码:

    1. import React from "react";
    2. import ReactFlow from "reactflow";
    3. import "reactflow/dist/style.css";
    4. const initialNodes = [
    5. {
    6. id: "1",
    7. type: "input",
    8. data: { label: "Mind Map" },
    9. position: { x: 0, y: 0 },
    10. },
    11. ];
    12. export default function MindNode() {
    13. return (
    14. "container">
  • );
  • }
  • 我们导入了项目所需的重要依赖项。然后,我们定义了一个名为 initialNodes 的数组。该数组包含了一个起始节点配置,每个节点都有几个属性。 MindNode 功能性的React组件返回 JSX ,用于渲染思维导图节点。

    从那里,导航到 App.jsx 在 src 目录/文件夹中,并替换以下代码以渲染函数 MindNode 。

    1. import React from "react";
    2. import MindNode from "./components/node";
    3. function App() {
    4. return (
    5. "App">
  • );
  • }
  • export default App;
  • 最后,在这个阶段,导航到 src/main.jsx 并粘贴下面的代码:

    1. import React from "react";
    2. import ReactDOM from "react-dom/client";
    3. import App from "./App.jsx";
    4. import "./index.css";
    5. ReactDOM.createRoot(document.getElementById("root")).render(
    6. );

    上面的代码设置并渲染了你的主要React组件App到HTML DOM中。从目前的代码中,你应该得到下面所示的输出:

    44a407d448d2f749f74a5e834cb253a0.gif

    自定义节点外观

    您可以通过修改React Flow应用程序中节点的外观,根据其类型或属性构建具有不同样式和视觉属性的节点。现在导航到 src/node.jsx 并将以下代码添加到其中:

    1. import React, { useState } from "react";
    2. import ReactFlow, { MiniMap, useNodesState } from "reactflow";
    3. import "reactflow/dist/style.css";
    4. const initialNodes = [
    5. {
    6. id: "1",
    7. type: "input",
    8. data: { label: "Mind Map" },
    9. position: { x: 0, y: 0 },
    10. },
    11. ];
    12. export default function MindNode() {
    13. const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
    14. const [name, setName] = useState("");
    15. const addNode = () => {
    16. setNodes((e) =>
    17. e.concat({
    18. id: (e.length + 1).toString(),
    19. data: { label: `${name}` },
    20. position: {
    21. x: Math.random() * window.innerWidth,
    22. y: Math.random() * window.innerHeight,
    23. },
    24. })
    25. );
    26. };
    27. return (
    28. "container">
    29. nodeColor={(n) => {
    30. if (n.type === "input") return "blue";
    31. return "#FFCC00";
    32. }}
    33. />
    34. type="text"
    35. onChange={(e) => setName(e.target.value)}
    36. name="title"
    37. />
    38. Add Node
  • );
  • }
  • 上面的代码创建了一个基本的思维导图应用程序。用户可以向地图添加自定义标签,并根据节点的类型改变其外观。Reactflow库包含处理思维导图状态和交互性所需的组件和钩子。 miniMap 允许您从小的视角看到整个屏幕。

    添加互动性

    93c4d4105d9c1d73dffa25c6b4b732c8.gif

    从上面的片段中我们可以看到,我们无法连接节点。允许用户与节点和边进行交互,比如建立连接和与节点进行交互,是为思维导图应用程序增加互动性的一种方式。请将以下代码复制并粘贴到您的 src/node.jsx 中。

    1. import React, { useState, useCallback } from "react";
    2. import ReactFlow, {
    3. MiniMap,
    4. Controls,
    5. useNodesState,
    6. useEdgesState,
    7. addEdge,
    8. } from "reactflow";
    9. import "reactflow/dist/style.css";
    10. const initialNodes = [
    11. {
    12. id: "1",
    13. type: "input",
    14. data: { label: "Mind Map" },
    15. position: { x: 0, y: 0 },
    16. },
    17. ];
    18. const initialEdges = [];
    19. const onLoad = (reactFlowInstance) => {
    20. reactFlowInstance.fitView();
    21. };
    22. export default function MindNode() {
    23. const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
    24. const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
    25. const [name, setName] = useState("");
    26. const addNode = () => {
    27. setNodes((e) =>
    28. e.concat({
    29. id: (e.length + 1).toString(),
    30. data: { label: `${name}` },
    31. position: {
    32. x: Math.random() * window.innerWidth,
    33. y: Math.random() * window.innerHeight,
    34. },
    35. })
    36. );
    37. };
    38. const onConnect = useCallback(
    39. (params) => setEdges((eds) => addEdge(params, eds)),
    40. [setEdges]
    41. );
    42. return (
    43. "container">
    44. nodes={nodes}
    45. edges={edges}
    46. onNodesChange={onNodesChange}
    47. onEdgesChange={onEdgesChange}
    48. onConnect={onConnect}
    49. onLoad={onLoad}
    50. >
    51. nodeColor={(n) => {
    52. if (n.type === "input") return "blue";
    53. return "#FFCC00";
    54. }}
    55. />
    56. type="text"
    57. onChange={(e) => setName(e.target.value)}
    58. name="title"
    59. />
    60. Add Node
    61. );
    62. }

    上面的代码使用useEdgesState来管理边的状态,并使用useCallback定义onConnect来处理节点边(连接)的生成。之后,我们使用所需的边、事件处理程序和缩放和平移显示的控件来渲染一个ReactFlow组件。

    保存和加载思维导图

    在基于React Flow的应用中保存和加载思维导图是一个重要的功能,允许用户保存和恢复他们的工作。这个功能提高了您的应用的可用性和价值。

    保存思维导图

    保存思维导图时,您必须收集表示思维导图中节点和边的数据。这些信息应该被转换成可存储的格式,比如JSON。您可以利用元素的状态来捕捉思维导图的当前状态。导航到 src 文件夹并创建一个新文件 storage.jsx ,添加以下代码:

    1. export const saveMindMap = (nodes, edges) => {
    2. const data = { nodes, edges };
    3. localStorage.setItem("mindMapData", JSON.stringify(data));
    4. };

    以上代码定义了 saveMindMap 函数,该函数将思维导图的数据,包括节点和边的信息,保存到浏览器的本地存储中。本地存储是一种在用户设备上存储少量数据的简单方法。

    加载思维导图:

    加载思维导图与保存相反。您获取保存的数据,反序列化它,然后使用加载的数据更新React Flow画布。要加载保存的思维导图,请将以下代码粘贴到您的 src/storage.jsx 中。

    1. export const loadMindMap = () => {
    2. const data = localStorage.getItem("mindMapData");
    3. return data ? JSON.parse(data) : null;
    4. };

    上面的代码从本地存储中检索序列化数据,将其解析为对象并返回该对象。接下来,将以下函数导入到您的组件中,并使用它们来保存和加载思维导图:

    1. import React, { useState, useCallback, useEffect } from "react";
    2. import ReactFlow, {
    3. MiniMap,
    4. Controls,
    5. useNodesState,
    6. useEdgesState,
    7. addEdge,
    8. Background,
    9. } from "reactflow";
    10. import { saveMindMap, loadMindMap } from "./Storage";
    11. import "reactflow/dist/style.css";
    12. const initialNodes = [
    13. {
    14. id: "1",
    15. type: "input",
    16. data: { label: "Mind Map" },
    17. position: { x: 0, y: 0 },
    18. style: { border: "20px solid #9999" },
    19. },
    20. ];
    21. const initialEdges = [];
    22. const onLoad = (reactFlowInstance) => {
    23. reactFlowInstance.fitView();
    24. };
    25. export default function MindNode() {
    26. const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
    27. const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
    28. const [name, setName] = useState("");
    29. const addNode = () => {
    30. setNodes((e) =>
    31. e.concat({
    32. id: (e.length + 1).toString(),
    33. data: { label: `${name}` },
    34. position: {
    35. x: Math.random() * window.innerWidth,
    36. y: Math.random() * window.innerHeight,
    37. },
    38. style: { border: "10px solid #9999" },
    39. })
    40. );
    41. };
    42. const onConnect = useCallback(
    43. (params) => setEdges((eds) => addEdge(params, eds)),
    44. [setEdges]
    45. );
    46. const handleSaveClick = () => {
    47. saveMindMap(nodes, edges);
    48. console.log(nodes);
    49. };
    50. const handleLoadClick = () => {
    51. const loadedData = loadMindMap();
    52. if (loadedData) {
    53. setNodes(loadedData.nodes);
    54. setEdges(loadedData.edges);
    55. console.log(loadedData);
    56. }
    57. };
    58. const refreshPage = () => {
    59. window.location.reload();
    60. };
    61. // const nodeOrigin = [0.5, 0.5];
    62. const connectionLineStyle = {
    63. stroke: "#9999",
    64. strokeWidth: 3,
    65. };
    66. const defaultEdgeOptions = { style: connectionLineStyle, type: "mindmap" };
    67. return (
    68. "container">
    69. nodes={nodes}
    70. edges={edges}
    71. onNodesChange={onNodesChange}
    72. onEdgesChange={onEdgesChange}
    73. connectionLineStyle={connectionLineStyle}
    74. defaultEdgeOptions={defaultEdgeOptions}
    75. onConnect={onConnect}
    76. onLoad={onLoad}
    77. >
    78. "dots" gap={12} size={1} />
    79. nodeColor={(n) => {
    80. if (n.type === "input") return "blue";
    81. return "#FFCC00";
    82. }}
    83. />
    84. type="text"
    85. onChange={(e) => setName(e.target.value)}
    86. name="title"
    87. />
    88. Add Node
    89. Save Mind Map
    90. Load Mind Map
    91. Refresh
    92. );
    93. }

    通过这些更改,您现在有一个用于保存当前思维导图数据的 handleSaveClick 函数,一个用于加载先前保存的思维导图数据的 handleLoadClick 函数,以及一个用于重新加载页面到其原始形式的 refreshPage 函数。

    界面设计的样式化

    我们的开发过程几乎完成了。让我们根据我们的特定需求来定制我们的设计。导航到 src/index.css 并替换以下代码:

    1. body {
    2. margin: 0;
    3. background-color: #f8f8f8;
    4. }
    5. #container {
    6. height: 90vh;
    7. width: 100%;
    8. }
    9. input {
    10. border: 1px solid rgb(203, 186, 186);
    11. padding: 4px 8px;
    12. border-radius: 5px;
    13. font-weight: 700;
    14. background: transparent;
    15. height: 100%;
    16. color: #222;
    17. }
    18. input:focus {
    19. border: none;
    20. outline: none;
    21. background: rgba(255, 255, 255, 0.25);
    22. pointer-events: all;
    23. }
    24. button {
    25. padding: 6px 8px;
    26. border-radius: 5px;
    27. border: none;
    28. background-color: #008cba;
    29. color: white;
    30. }
    31. button:hover {
    32. background-color: rgb(69, 69, 229);
    33. }
    34. input[type="text"] {
    35. padding: 8px;
    36. margin-right: 10px;
    37. border: 1px solid #ccc;
    38. border-radius: 4px;
    39. }
    40. .react-flow {
    41. border: 3px solid #9999;
    42. border-radius: 10px;
    43. }
    44. /* .react-flow_nodes {
    45. color: #a02828;
    46. } */
    47. #two {
    48. background-color: #4caf50;
    49. margin: 5px;
    50. }
    51. #two:hover {
    52. background-color: #63c266;
    53. }
    54. #three {
    55. background-color: #f44336;
    56. margin: 2px;
    57. }
    58. #three:hover {
    59. background-color: rgb(190, 68, 68);
    60. }
    61. #four {
    62. background-color: rgb(86, 86, 6);
    63. }
    64. #four:hover {
    65. background-color: rgb(113,

    测试

    我们将进行一项测试,以了解我们的ReactFlow Mind应用程序的工作原理。

    79b6ce50b1bc19cd018cc99a098b2bd3.png

    请注意:您可以连接不同位置的节点,并且您还可以为每个节点指定一个期望的名称,以说明您的想法或项目。

    结束

    使用React Flow创建一个思维导图应用是一个有趣且多功能的项目,可以根据不同的用例进行调整,从头脑风暴会议到项目管理等等。在本指南中,我们已经涵盖了构建一个可工作的思维导图应用的重要步骤,例如设置开发环境,集成React Flow,修改节点外观,添加交互,并实现保存、加载和刷新功能。您可以根据需要添加更多功能和功能。

    由于文章内容篇幅有限,今天的内容就分享到这里,文章结尾,我想提醒您,文章的创作不易,如果您喜欢我的分享,请别忘了点赞和转发,让更多有需要的人看到。同时,如果您想获取更多前端技术的知识,欢迎关注我,您的支持将是我分享最大的动力。我会持续输出更多内容,敬请期待。

  • 相关阅读:
    【日拱一卒行而不辍20220921】自制操作系统
    java生产者 消费者模式概念讲解
    【Linux】进程信号(完整版) --- 信号产生 信号保存 信号捕捉 可重入函数 volatile SIGCHLD信号等
    悬镜云鲨SaaS三大核心能力 构筑下一代积极防御体系
    【夯实算法基础】最近公共祖先
    高校部署房产管理系统可实现那些目标?
    Pycharm与Gitlab交互
    【学习Docker(三)】Docker Mysql8.0.26的安装与卸载
    Row 28 was cut by GROUP_CONCAT()
    java基本概念(更新中)
  • 原文地址:https://blog.csdn.net/Ed7zgeE9X/article/details/134453354