Vue‑Flow 从零入门实战|AI‑Agent 拓扑图开发

Vue‑Flow 是对标 React‑Flow(@xyflow/react) 的 Vue3 图编辑库,用来做DAG工作流、Agent流程图、拓扑图。

官网:https://vueflow.dev/guide

技术栈:Vue3 + Vite + JavaScript

一、什么是 Vue‑Flow

Vue‑Flow 是社区维护的图编辑组件库,核心能力:节点拖拽、画布平移缩放、锚点连线、自定义节点。

底层逻辑:两份普通JS数组驱动整个画布

  1. nodes:节点数组,画布上每一个方块
  2. edges:连线数组,节点和节点之间的连线

核心公式:修改 nodes / edges → 画布自动响应更新。

字段基础结构

node 节点

js 复制代码
{
  id: "唯一字符串",
  position: {x: 数字, y:数字}, //画布坐标
  type: "default", //default 使用内置默认节点;自定义节点填注册的type名称
  data: {} //业务自定义数据,节点显示的内容全部放这里
}

edge 连线

js 复制代码
{
  id:"连线唯一ID",
  source:"源节点id",
  target:"目标节点id"
}

二、快速搭建最小 Demo

1. 创建项目

bash 复制代码
pnpm create vite flow‑demo --template vue
cd flow‑demo
pnpm install

2. 安装核心依赖

扩展包@vue‑flow/background等新版存在导出问题,初学先不用。

bash 复制代码
pnpm add @vue-flow/core

3. 最小可运行代码 App.vue

html 复制代码
<template>
  <div class="wrap">
    <VueFlow
      v-model:nodes="nodes"
      v-model:edges="edges"
      @connect="handleConnect"
    ></VueFlow>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { VueFlow, useVueFlow } from '@vue-flow/core'
// 必须导入核心样式,否则节点、锚点丢失
import '@vue-flow/core/dist/style.css'
import '@vue-flow/core/dist/theme-default.css'

const flow = useVueFlow()

const nodes = ref([
  {
    id: 'a',
    position: { x: 50, y: 100 },
    type: 'default',
    data: { label: '节点1' }
  },
  {
    id: 'b',
    position: { x: 300, y: 100 },
    type: 'default',
    data: { label: '节点2' }
  }
])

const edges = ref([
  { id: 'e‑a‑b', source: 'a', target: 'b' }
])

// 用户拖拽锚点生成连线触发
const handleConnect = (info) => {
  console.log('新建连线', info)
}
</script>

<style scoped>
.wrap {
  width: 100%;
  height: 500px; /* ⚠️画布容器必须写固定高度,不会自动撑开 */
  border:1px solid #ccc;
}
</style>

运行 pnpm dev

可以做的操作:拖拽节点、画布平移、滚轮缩放、拖拽锚点连线。

三、基础能力扩展

1. 程序控制:新增 / 删除节点

nodes、edges 本质就是数组,直接操作数组即可更新画布。

js 复制代码
//新增节点
const addNode = ()=>{
  const newId = "node‑" + Date.now()
  nodes.value.push({
    id:newId,
    position:{x:100,y:200},
    type:"default",
    data:{label:"新节点"}
  })
}

//删除节点,同时清理关联连线
const deleteNodeById = (delId)=>{
  nodes.value = nodes.value.filter(n=>n.id!==delId)
  edges.value = edges.value.filter(e=> e.source!==delId && e.target!==delId)
}

2. 异步后端接口渲染画布(真实业务高频)

场景:从后端拿到 nodes、edges 数据渲染拓扑图。

关键点:后端返回数据结构必须匹配 Vue‑Flow 的 node/edge 格式;拿到数据直接赋值覆盖 ref;加载完调用fitView()自动适配视口。

js 复制代码
//模拟后端请求
async function loadGraph(){
  // const res = await axios.get("/api/graph")
  //模拟接口返回
  const remote = {
    nodes:[
      {id:"r1",position:{x:50,y:80},type:"default",data:{label:"Agent‑A"}}
    ],
    edges:[]
  }
  nodes.value = remote.nodes
  edges.value = remote.edges
  //自动缩放画布,把全部节点展示在视口中
  flow.fitView({padding:30})
}

3. 常用事件监听

html 复制代码
<VueFlow
  @connect="handleConnect"
  @node‑click="onNodeClick"
  @node‑drag‑stop="onDragStop"
  @edge‑click="onEdgeClick"
/>
  • @connect:拖拽锚点生成连线
  • @node‑click:点击节点
  • @node‑drag‑stop:节点拖拽结束,适合保存节点新坐标回后端
  • @edge‑click:点击连线

四、生产环境性能优化

节点数量少(<50)不需要优化;上百个节点才会出现卡顿。

  1. 使用 shallowRef,减少深度响应式开销
    ref会递归代理数组内部每一个 node 对象,大量节点性能差。
    shallowRef仅对数组外层做响应式,不代理内部对象。

注意:shallowRef 禁止直接 push,必须整体赋值替换数组。

js 复制代码
import { shallowRef } from 'vue'
const nodes = shallowRef([])
// ✅正确
nodes.value = [...nodes.value, newNode]
// ❌禁止
nodes.value.push(newNode)
  1. 开启虚拟渲染:上千节点场景
    只渲染视口内可见节点,不在视口的节点不渲染 DOM。
html 复制代码
<VueFlow :virtualization="true"/>

限制:开启虚拟渲染,节点尽量使用固定高度,动态高度会有 bug。

  1. 业务层面优化
  • 不要在node‑drag(拖拽过程高频事件)中做请求、复杂计算,放到node‑drag‑stop。
  • 批量更新 nodes/edges,一次性赋值,不要循环逐个 push。
  • 大量连线避免开启animated:true流动动画,消耗 CPU。
  • 事件回调不要写内联箭头函数,避免每次渲染生成新引用触发重渲染。

五、常见踩坑清单

  1. 外层容器必须设置 height,VueFlow 不会自动撑开高度,否则画布看不见。
  2. 必须导入 core 的style.css,否则锚点、节点样式丢失。
  3. node.id、edge.id 必须全局唯一,重复 id 会出现诡异 bug。
  4. <Handle>连接桩只能写在自定义节点组件内部,不能直接写在画布根模板。
  5. 新版扩展包@vue‑flow/background直接导入 dist/style.css 会报 exports 导出错误。

六、业务场景:AI Agent 渗透拓扑图

  • 自定义节点 + Handle 连接桩,渲染多 Agent 协作 DAG 拓扑。
  • 接口拆分:图谱静态结构、任务渗透进度轮询两个接口,按需更新画布,避免大体积数据频繁传输。
  • 对图编辑库做分包懒加载,不阻塞首屏登录页。
相关推荐
m0_587383001 小时前
碰碰好评卡功能落地实战 从需求梳理到上线部署全流程实操指南
java·linux·服务器·前端·javascript·vue.js·人工智能
keyipatience1 小时前
CSS 学习(1):语法、引入方式、选择器、字体与背景
前端·css·html
程序人生8881 小时前
本地向量底座怎么搭?DocConverter Web 的 BGE 嵌入模型、ChromaDB 与外部 Milvus 接入
前端·milvus
恋猫de小郭1 小时前
Flutter Android 改动:APK 不再允许通过 Intent 动态修改 Engine 参数
android·前端·flutter
ck0135791 小时前
视频转 GIF 的基本流程与文件大小优化
前端·测试工具·html·音视频·视频
郝学胜-神的一滴2 小时前
Web安全入门:读懂Web世界里的攻防
前端·网络·后端·安全·web安全·hibernate
Amos_Web2 小时前
Rspack 源码解析(二十四):AssetPlugin 如何让图片同时是「URL 字符串」和「真实文件」
前端·rust·前端框架
lexiangqicheng2 小时前
1,自定义表单通俗理解-PC设计APP渲染
java·前端·javascript
其实防守也摸鱼2 小时前
Codex 下载与本地部署实战指南
linux·服务器·前端·数据库·算法·ai