Vue Flow实战:5分钟搞定自定义节点拖拽与连线(附完整代码)
上周,团队里一个刚接手流程设计模块的后端同事跑来问我:“哥,前端那边要一个能拖拽、能连线、还能保存的流程图,有没有什么库能快速搞定?” 我看着他焦虑的眼神,想起了自己第一次面对类似需求时的茫然。市面上流程图库不少,但要么太重,要么定制性差,要么文档晦涩。我拍了拍他肩膀:“试试 Vue Flow,今天下班前就能让你看到可运行的Demo。”
Vue Flow 是一个基于 Vue 3 的流程图库,它最大的魅力在于组件化思维与声明式API的完美结合。你不用再和复杂的 Canvas API 搏斗,也不用担心状态管理一团糟。它就像乐高积木,提供了节点(Node)、边(Edge)、连接点(Handle)等核心组件,让你能用写 Vue 组件的方式,轻松搭建出交互复杂的流程图应用。无论是简单的审批流、复杂的系统架构图,还是需要高度自定义的业务流程图,Vue Flow 都能优雅胜任。这篇文章,就是为你——那位需要在项目中快速集成流程图功能的中级开发者——准备的一份“开箱即用”实战指南。我们不谈空洞的理论,直接上手代码,用最短的时间,打造一个功能完备的交互式流程图编辑器。
1. 环境搭建与项目初始化:从零到一的五分钟
别被“流程图”三个字吓到,以为要配置一堆复杂的构建工具。得益于 Vue 3 和 Vite 的现代前端工具链,搭建一个 Vue Flow 的开发环境只需要几分钟。我们追求的是效率,所以一切从简,但又不失工程化的严谨。
首先,确保你的开发环境已经安装了 Node.js(建议版本 16+)和 npm 或 yarn。然后,打开终端,我们一步步来。
第一步:创建 Vue 3 项目。 我强烈推荐使用 Vite,它的启动速度和热更新体验远超 Webpack。
npm create vue@latest vue-flow-demo
# 或者
yarn create vue vue-flow-demo
在创建向导中,你可以按需选择 TypeScript、Router、Pinia 等,但为了演示的纯粹性,我们这里只选择 TypeScript 即可。创建完成后,进入项目目录并安装基础依赖。
第二步:安装 Vue Flow 及其配套组件。 Vue Flow 采用了模块化设计,核心功能与辅助组件分离,你可以按需引入。
cd vue-flow-demo
npm install @vue-flow/core @vue-flow/background @vue-flow/controls @vue-flow/minimap
# 或者
yarn add @vue-flow/core @vue-flow/background @vue-flow/controls @vue-flow/minimap
这里我们安装了四个包:
@vue-flow/core: 核心库,包含节点、边、画布等基础组件和钩子。@vue-flow/background: 提供画布背景(如网格、点阵),增强视觉参考。@vue-flow/controls: 提供缩放、适配视图、全屏等交互控件。@vue-flow/minimap: 提供一个画布的缩略导航图,在处理大型流程图时非常有用。
第三步:清理与准备。 进入 src/App.vue,清空默认内容,我们从一个干净的画布开始。同时,在 src/components 目录下,创建一个 FlowChart.vue 文件,这将是我们流程图编辑器的主组件。
现在,你的项目结构应该大致如下:
vue-flow-demo/
├── src/
│ ├── components/
│ │ └── FlowChart.vue (待创建)
│ ├── App.vue
│ └── main.ts
├── package.json
└── vite.config.ts
提示:如果你在安装后遇到类型错误,可以尝试安装
@vue-flow/core的类型定义包@types/__vue-flow__core,或者检查你的tsconfig.json中是否包含了正确的类型声明路径。不过,Vue Flow 自身通常已内置了良好的 TypeScript 支持。
环境准备就绪,接下来我们进入核心环节:构建一个可拖拽、可连线的画布。
2. 构建核心画布与基础交互
让我们先搭建一个最基础的、能显示节点和边的画布。在 src/components/FlowChart.vue 中,我们开始编写代码。Vue Flow 的核心是 VueFlow 组件,它管理着所有节点和边的状态。
首先,引入必要的组件和样式:
<template>
<div class="flow-container">
<VueFlow
v-model:nodes="nodes"
v-model:edges="edges"
:fit-view-on-init="true"
@connect="onConnect"
>
<Background variant="dots" :gap="20" />
<Controls />
<MiniMap />
</VueFlow>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { VueFlow, useVueFlow, Connection, Node, Edge } from '@vue-flow/core'
import { Background } from '@vue-flow/background'
import { Controls } from '@vue-flow/controls'
import { MiniMap } from '@vue-flow/minimap'
import '@vue-flow/core/dist/style.css'
import '@vue-flow/core/dist/theme-default.css'
// 定义节点和边的响应式数据
const nodes = ref<Node[]>([
{ id: '1', position: { x: 0, y: 0 }, data: { label: '开始节点' } },
{ id: '2', position: { x: 250, y: 100 }, data: { label: '处理节点' } },
])
const edges = ref<Edge[]>([
{ id: 'e1-2', source: '1', target: '2', label: '流程' },
])
// 处理连线事件
function onConnect(params: Connection) {
edges.value.push({
...params,
id: `edge-${params.source}-${params.target}-${Date.now()}`,
animated: true,
style: { stroke: '#10b981' },
})
}
</script>
<style scoped>
.flow-container {
width: 100%;
height: 600px;
border: 1px solid #e5e7eb;
border-radius: 8px;
}
</style>
这段代码做了

5万+

被折叠的 条评论
为什么被折叠?



