极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

news2024/9/21 4:23:39

目录

极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

一、环境要求

二、初识Vue Flow

2.1、安装Vue Flow

2.2、Vue Flow构成

2.3、一个小坑

2.4、入门案例

三、Vue Flow优秀的自定义功能

3.1、引入

3.2、节点与连线的自定义

①打样(做模板)

②模版取名

③替换模版

 3.3、节点与连线的事件

①节点事件

②连线事件

3.4、句柄(handles)

四、一个优质的案例

五、总结


极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图

        Vue Flow的入门门槛要高不少,毕竟找不到中文文档,反正我是不太喜欢看纯英文的文档的。不过没关系,看完这篇还用不好Vue Flow请来找我麻烦。

一、环境要求

        Node.js v20 或更高版本

        Vue 3.3 或更高版本

        前者,没有装nvm建议装一个nvm,noder没有nvm是行不通的。后者意味着Vue Flow不支持Vue2,据说有些辅助组件可以让部分功能在Vue中使用。

Tips:

        如果把我的源码抄过去都跑不动,要么是依赖没有装好,要么是依赖的版本不对,Vue Flow的版本更迭是会伴随着API的更迭的,所以可以安装特定版本的Vue Flow来解决问题。我的Vue Flow版本是:​v1.39.0​

package.json:

    "@vue-flow/background": "^1.3.0",

    "@vue-flow/controls": "^1.1.2",

    "@vue-flow/core": "^1.38.5",

    "@vue-flow/minimap": "^1.5.0",

二、初识Vue Flow

2.1、安装Vue Flow

        根据自己的包管理器安装

不习惯用add就用install,也没问题

npm add @vue-flow/core

pnpm add @vue-flow/core

yarn add @vue-flow/core

2.2、Vue Flow构成

        在 Vue Flow 中,图由节点和边组成,每个节点或边都需要一个唯一的ID,节点还需要 XY 位置,而边需要 source 和 target 节点 ID,具体参照下方示例中的数据。

2.3、一个小坑

        我最开始在官网上找案例的时候,发现除了教程案例以外的所有多组件案例都跑不动。不要只顾着怀疑自己,因为官网上的案例就是跑不动的。

        原因在于:

为了确保 Vue Flow 正确显示,请确保包含必要的样式。

/* these are necessary styles for vue flow */

@import '@vue-flow/core/dist/style.css';

/* this contains the default theme, these are optional styles */

@import '@vue-flow/core/dist/theme-default.css';

         是的,官网复杂案例全都没有添加这两行代码,估计是写文档的程序员被push的太狠了,抓紧写了几个案例就把代码放上来,没有意识到自己是全局引入(我猜的)了这两行代码,并且没有做任何提示。

        但对于我们来说,只是为了画几个流程图的话,全局引入只会让代码变得冗余。局部引入就够了,把这两行放到style中官网的复杂案例就都可以执行了。

2.4、入门案例

        请注意,这个代码确定能跑,如果跑不动请先检查依赖。

        结构非常简单,定义了一个节点数据数组,一个连线数据数组,然后绑定给VueFlow组件即可。

<script setup>
import { ref } from "vue";
import { VueFlow } from "@vue-flow/core";

const nodes = ref([
  // an input node, specified by using `type: 'input'`
  {
    id: "1",
    type: "input",
    position: { x: 250, y: 5 },
    // all nodes can have a data object containing any data you want to pass to the node
    // a label can property can be used for default nodes
    data: { label: "Node 1" },
  },

  // default node, you can omit `type: 'default'` as it's the fallback type
  {
    id: "2",
    position: { x: 100, y: 100 },
    data: { label: "Node 2" },
  },

  // An output node, specified by using `type: 'output'`
  {
    id: "3",
    type: "output",
    position: { x: 400, y: 200 },
    data: { label: "Node 3" },
  },

  // this is a custom node
  // we set it by using a custom type name we choose, in this example `special`
  // the name can be freely chosen, there are no restrictions as long as it's a string
  {
    id: "4",
    type: "special", // <-- this is the custom node type name
    position: { x: 800, y: 200 },
    data: {
      label: "Node 4",
      hello: "world",
    },
  },
]);

const edges = ref([
  // default bezier edge
  // consists of an edge id, source node id and target node id
  {
    id: "e1->2",
    source: "1",
    target: "2",
  },

  // set `animated: true` to create an animated edge path
  {
    id: "e2->3",
    source: "2",
    target: "3",
    animated: true,
  },

  // a custom edge, specified by using a custom type name
  // we choose `type: 'special'` for this example
  {
    id: "e3->4",
    type: "special",
    source: "3",
    target: "4",

    // all edges can have a data object containing any data you want to pass to the edge
    data: {
      hello: "world",
    },
  },
]);
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges" style="height: 100vh; width: 100vw">
  </VueFlow>
</template>

<style>
/* import the necessary styles for Vue Flow to work */
@import "@vue-flow/core/dist/style.css";

/* import the default theme, this is optional but generally recommended */
@import "@vue-flow/core/dist/theme-default.css";
</style>

三、Vue Flow优秀的自定义功能

3.1、引入

        首先,预定义的配置项就不介绍了,上面的案例基本就是全部的预定义配置了,这一点和mermaid完全无法相比,但是你要用预定义的配置为什么不直接用mermaid呢?那个更简单清爽。

        Vue Flow的特点就是,什么都可以要,什么都要自己写。

        相比于mermaid来说,Vue Flow接受的数据更复杂冗长,并且预定义的内容极少,连默认的布局都没有(节点通过position控制位置,很容易重叠)。但是Vue Flow提供的自定义API非常丰富并且强大。

3.2、节点与连线的自定义

        自定义三步走:打样取名做替换。

①打样(做模板)

        做一个节点或者连线的模版,比如我需要一个长得像太阳的节点,那么我就写一个组件,然后把这个组件做成一个太阳的样子。

②模版取名

        给自己做的模版取一个名字,比如就叫sun,然后将想要使用这个模版的节点的type属性全部改成"sun"。

③替换模版

        在<VueFlow>标签之间添加如下代码,主要关注插槽名称“#node-sun”意味着所有type为sun的节点都使用这个插槽的模版。比如我设计了一种连线取名为darge,那么插槽名就是“#edge-darge”。

// 在script中引入
import sunNode from "./sunNode.vue";

<template>
  <div class="layout-flow">

    <VueFlow
      :nodes="nodes"
      :edges="edges"
      @nodes-initialized="layoutGraph('TB')"
    >
      <template #node-sun="props">
        <div class="sunNode">
          <span>{{ props.data.label }}</span>
        </div>
      </template>
    </VueFlow>
  </div>

</template>
 3.3、节点与连线的事件

        该有的事件应有尽有,不得不佩服Vue Flow的完善与强大。

①节点事件

        这是我比较建议的用法,比较简洁

<script setup>
import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core'

const nodes = ref([
  {
    id: '1',
    data: { label: 'Node 1' },
    position: { x: 50, y: 50 },
  },
])
  
function logEvent(name, data) {
  console.log(name, data)
}
</script>

<template>
  <!-- bind listeners to the event handlers -->
  <VueFlow
    :nodes="nodes"
    @node-drag-start="logEvent('drag start', $event)"
    @node-drag="logEvent('drag', $event)"
    @node-drag-stop="logEvent('drag stop', $event)"
    @node-click="logEvent('click', $event)"
    @node-double-click="logEvent('dblclick', $event)"
    @node-contextmenu="logEvent('contextmenu', $event)"
    @node-mouse-enter="logEvent('mouseenter', $event)"
    @node-mouse-leave="logEvent('mouseleave', $event)"
    @node-mouse-move="logEvent('mousemove', $event)"
  />
</template>

        也可以使用useVueFlow这个API,将这些事件转化为钩子,我觉得优势不明显,写起来也冗余。

<script setup>
import { ref } from 'vue'  
import { VueFlow, useVueFlow } from '@vue-flow/core'

// useVueFlow provides access to the event handlers
const { 
  onNodeDragStart, 
  onNodeDrag,
  onNodeDragStop, 
  onNodeClick, 
  onNodeDoubleClick, 
  onNodeContextMenu, 
  onNodeMouseEnter, 
  onNodeMouseLeave, 
  onNodeMouseMove 
} = useVueFlow()
  
const nodes = ref([
  {
    id: '1',
    data: { label: 'Node 1' },
    position: { x: 50, y: 50 },
  },
])
  
// bind listeners to the event handlers
onNodeDragStart((event) => {
  console.log('Node drag started', event)
})

onNodeDrag((event) => {
  console.log('Node dragged', event)
})

onNodeDragStop((event) => {
  console.log('Node drag stopped', event)
})
  
// ... and so on  
</script>

<template>
  <VueFlow :nodes="nodes" />
</template>
②连线事件

        连线事件也可以使用useVueFlow这个API,用法和上方一样,我就不赘述了,这里展示一下有哪些事件API。

<script setup>
import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core'

const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  },
])

const edges = ref([
  {
    id: 'e1->2',
    source: '1',
    target: '2',
  },
])
  
function logEvent(eventName, data) {
  console.log(eventName, data)
}
</script>

<template>
  <VueFlow
    :nodes="nodes"
    :edges="edges"
    @edge-click="logEvent('edge clicked', $event)"
    @edge-double-click="logEvent('edge double clicked', $event)"
    @edge-context-menu="logEvent('edge context menu', $event)"
    @edge-mouse-enter="logEvent('edge mouse enter', $event)"
    @edge-mouse-leave="logEvent('edge mouse leave', $event)"
    @edge-mouse-move="logEvent('edge mouse move', $event)"
    @edge-update-start="logEvent('edge update start', $event)"
    @edge-update="logEvent('edge update', $event)"
    @edge-update-end="logEvent('edge update end', $event)"
  />
</template>
3.4、句柄(handles)

        句柄是通常放置在节点边界上的小圆圈。它们用于通过将连接线从一个手柄拖动到另一个手柄来将节点连接在一起,从而在节点之间形成连接(边缘)。句柄是 VueFlow 的重要组成部分,因为它们是用户在节点之间创建边的主要交互点。如果没有句柄,基本上不可能在节点之间创建边,因为句柄用于计算边的源点和目标点。

        简单来说,就是两个节点连接需要通过句柄,如果没有句柄就无法连接。句柄就是连线两端的端点。常用在自定义节点的组件中,用来指定连线的起始点。

        句柄handdle需要设置两个属性,一个是类型(source/target),一个是位置(Top、Right、Bottom、Left),示例如下:

<script setup>
import { Handle } from '@vue-flow/core'
  
defineProps(['id', 'sourcePosition', 'targetPosition', 'data'])
</script>

<template>
  <Handle type="source" :position="sourcePosition" />
  
  <span>{{ data.label }}</span>
  
  <Handle type="target" :position="targetPosition" />
</template>

四、一个优质的案例

        案例具体代码请访问:Layouting | Vue Flow

        将所有组件代码复制到您的项目中即可,请注意相对路径关系,如果您没有全局引入2.3部分的内容,请在style中添加:

<style>
@import "@vue-flow/core/dist/style.css";
@import "@vue-flow/core/dist/theme-default.css";


// ...其他的css样式
</style>

五、总结

        相比于mermaid,Vue Flow将注意力更多的转到灵活自定义的接口而不是大量的预定义模版,“什么都可以有,什么都要自己写。”是Vue Flow的典型特征。如果您想发挥自己天马行空的想象力,或者满足复杂的项目流程需求,Vue Flow一定能满足您的预期。

        博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

        更多优质内容,请关注:

 JS语法与Vue开发:

        Vue 性能革命:揭秘前端优化的终极技巧

        属性描述符初探——Vue实现数据劫持的基础

        你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解

        最细最有条理解析:事件循环(消息循环)是什么?进程与线程的定义、关系与差异

        路由通配符,小小的字符有大大的作用,你真的熟悉吗? 

        管理数据必备!侦听器watch用法详解

        什么是深拷贝?深拷贝和浅拷贝有什么区别

        对象数据的读取,看这一篇就够了!

        通过array.every()实现数据验证、权限检查和一致性检查,array.some与array.every的区别

        通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理

        通过array.map()实现数据转换、创建派生数组、异步数据流处理、搜索和过滤等需求

        通过array.reduce()实现数据汇总、条件筛选和映射、对象属性的扁平化、转换数据格式等

        通过array.filter()实现数组的数据筛选、数据清洗和链式调用

        多维数组操作,不要再用遍历循环foreach了,来试试数组展平的小妙招!

        别再用双层遍历循环来做新旧数组对比,寻找新增元素了!

        shpfile转GeoJSON且控制转化精度;如何获取GeoJSON?GeoJson结构详解

        Mapbox添加行政区矢量图层、分级设色图层、自定义鼠标悬浮框、添加天地图底图等

Element plus拓展:

        通过el-tree自定义渲染网页版工作目录,实现鼠标悬浮显示完整名称等

        el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能

        el-table中如何添加渐变色带、多色色带

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1957151.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL - 通过SQL语句导出数据到CSV文件

在 MySQL 中&#xff0c;可以使用 SELECT ... INTO OUTFILE 语句将查询结果导出为 CSV 文件&#xff0c;然后再将 CSV 文件转换为 Excel 格式。以下是一个示例&#xff1a; SELECT column1, column2, column3 INTO OUTFILE /path/to/file.csv FIELDS TERMINATED BY , ENCLO…

git 迁移仓库的方法

git Git是一个开源的分布式版本控制系统&#xff0c;由Linus Torvalds在2005年创建&#xff0c;用于有效、高速地处理从小到大的项目管理。它最初是为Linux内核开发而设计的&#xff0c;但很快被广泛用于各种项目。 以下是Git的一些主要特性&#xff1a; 分布式架构&#xff…

接近传感器 - 从零开始认识各种传感器【第十七期】

1、什么是接近传感器 接近传感器常被用于检测物体的距离或者是否有物体靠近。它通常发射电磁场或电磁波&#xff08;例如红外线&#xff09;来探测物体的位置。当有物体靠近时&#xff0c;传感器会接收到反射的电磁波信号&#xff0c;从而触发相应的电路或者控制系统。它广泛应…

Helm(二)

一、Chart模板流程控制if_with_range 1.if 修改values.yaml cat > values.yaml <<EOF myname: yeunyi service: type: ClusterIP port: 80 myport: 8080 EOF 修改service.yaml cat > templates/service.yaml <<EOF apiVersion: v1 kind: Service met…

TC8:SOMEIP_ETS_007-008

SOMEIP_ETS_007: echoBitfields 目的 检查位字段是否能够被顺利地发送和接收。 测试步骤 Tester:创建SOME/IP消息Tester:使用method echoBitfields发送SOME/IP消息DUT:返回method响应消息,其中位字段的顺序与请求相比是反向的期望结果 3、DUT:返回method响应消息,其中位…

微软蓝屏”事件暴露了网络安全哪些问题?

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

探秘数字孪生技术在智慧校园的应用

在当今教育信息化的浪潮中&#xff0c;数字孪生技术逐渐成为智慧校园建设的重要助推器。这一技术通过构建真实世界的数字化映像&#xff0c;不仅提升了校园管理的效率&#xff0c;更为师生的日常学习生活提供了全新的体验。首先&#xff0c;数字孪生可以将校园内的各类设施、环…

七夕告白攻略:天使智能体教你如何设计完美表白卡片!独属程序员地浪漫!

文章目录 &#x1f495;七夕浪漫告白天使&#x1f495;&#x1f495;浪漫风格的表白卡片设计&#x1f495;&#x1f495;甜蜜风格的表白卡片设计&#x1f495;&#x1f495;温馨风格的表白卡片设计&#x1f495;&#x1f495;幽默风格的表白卡片设计&#x1f495;&#x1f495;…

使用java读取本地文件内容并输出,java读取文件内容,节省内存开销

java使用FileInputStream读取本地文件内容 java使用Stream流读取本地文件内容 1.先在自己笔记本选一个目录创建文件&#xff0c;这里就选择在D盘创建一个 word.txt文件 随意输入内容例如 2.直接来直接复制代码运行 import java.io.*; import java.nio.file.Files; import ja…

rust sip电话(基于tauri 、pjsip库)

本文尝试下rust 的tauri 桌面运用 原因在于体积小 1、pjsip 提供了rust 接口官方的 rust demo 没编译出来 在git找了个sip-phone-rs-master https://github.com/Charles-Schleich/sip-phone-rs 可以自己编译下pjsip lib库替换该项目的lib 2、创建一个tauri demo 引用 [depe…

佐糖v1.7.2高级版,全能型AI图片处理App!

经常刷抖音的小伙伴应该都遇见过这种吧&#xff0c;修复老张片一张10块钱&#xff0c;老照片还原高清...这种看似很高端很神器&#xff0c;你以为真的有画师专门帮你来修复老张片吗&#xff1f;&#xff01;怎么可能...都是现在AI技术识别照片信息&#xff0c;然后给你生成的。…

全国禁毒知识竞赛--“我是答题王”竞赛规则

全国禁毒知识竞赛共分四轮&#xff0c;通过6支队伍最终分数高低&#xff0c;角逐出团队一、二、三等奖。第四轮各队派出1名代表进行车轮挑战&#xff0c;最终决出本届的“我是答题王”一、二、三等奖和个人答题王。 环节一&#xff1a;火线缉毒&a…

基于CNN的手写汉字识别系统的设计与实现

1 项目介绍 1.1 摘要 随着数字化技术的快速发展&#xff0c;手写汉字识别技术在多个领域展现出广泛的应用前景。为了提升手写汉字识别的准确率和泛化能力&#xff0c;本文通过构建一个基于卷积神经网络&#xff08;CNN&#xff09;的手写汉字识别系统&#xff0c;以应对不同书…

Nginx系列-11 HTTP消息处理流程

背景 了解Nginx处理HTTP请求的11个阶段&#xff0c;有助于理解和配置nginx、自定义模块、基于lua模块自定义功能。按如下配置&#xff0c;执行"curl http://localhost:8001/query/test.html"&#xff0c;如果读者对结果不是很确定&#xff0c;建议阅读本文。 serve…

免费pdf转word软件有哪些?5个软件帮助你快速进行文件转换

免费pdf转word软件有哪些&#xff1f;5个软件帮助你快速进行文件转换 将PDF文件转换为Word格式可以方便编辑和修改。以下是五款免费的PDF转Word软件&#xff0c;它们可以帮助你快速进行文件转换。 迅捷PDF转换器 这是一款设计简洁、操作便捷的PDF工具&#xff0c;它集成了多…

go语言day20 使用gin框架获取参数 使用自定义的logger记录日志

Golang 操作 Logger、Zap Logger 日志_golang zap-CSDN博客 目录 一、 从控制器中获取参数的几种形式 1&#xff09; 页面请求url直接拼接参数。 2&#xff09; 页面请求提交form表单 3&#xff09; 页面请求发送json数据&#xff0c;使用上下文对象c的BindJSON()方法接…

面试场景题系列--(4)设计一个支持敏感数据存储和传输安全的加解密平台--xunznux

文章目录 设计一个支持敏感数据存储和传输安全的加解密平台1. 设计背景2. 需求分析日常开发中的加解密程序常见问题解决方案具体来说系统主要用例过程和功能系统需求 3. 概要设计3.1 部署模型3.2 加解密调用流程 4. 详细设计4.1 密钥领域模型4.2 核心服务类设计4.3 加解密数据接…

张量网络碎碎念:从 SO3 到 SO2

在上两篇文献中&#xff0c;我像大家介绍了 多通道 模型在 AI for Science 任务中的应用。核心思路类似 CV 中&#xff0c;将灰白单通道拓展到 RGB 多通道&#xff0c;能够提升图片表征能力。&#xff08;见 图神经网络与分子表征&#xff1a;8. TFN&#xff09;痛点在于张量积…

昇思25天学习打卡营第4天|基础知识-数据变换 Transforms

目录 数据变换 Transforms 环境 Common Transforms Compose Vision Transforms Rescale Normalize HWC2CHW Text Transforms PythonTokenizer Lookup Lambda Transforms 补充知识 map方法&#xff1a; lambda函数 filter() 函数 数据变换 Transforms 通常情况下&…

新手小白也能做!十大跨境电商平台推荐

梦想着将你的商品推向世界吗&#xff1f;跨境电商不仅是一门生意&#xff0c;更是一场文化和创新的交流。但作为新手&#xff0c;面对众多平台&#xff0c;你可能会有些迷茫。别担心&#xff0c;我们为你精选了几个全球知名的跨境电商平台&#xff0c;从入驻条件到开店成本&…