Vue3项目怎么实现专业流程图?从0到1选工具、搭组件、做交互全指南
最近公司要上线一个供应链节点追踪的后台,产品经理明确指定用Vue3做,还要加拖拽式的流程图功能——能拖拽节点、连边、改属性、导出不同格式,看起来要求不低,一开始我也犯懵,查了不少资料踩了几个小坑才做出来,刚好整理成问答,给同样需要Vue3做流程图的朋友参考。
为什么Vue3比Vue2更适合做流程图?
很多人可能没太在意框架版本对这类可视化组件的影响,其实Vue3的几个核心特性刚好踩中了流程图的需求点:
响应式系统的优化更适配高频交互
流程图最常见的就是拖拽、缩放、连边时的实时反馈,Vue3用Proxy重写了响应式系统,比Vue2的Object.defineProperty快得多——尤其是节点和连线数据量大的时候(比如几百个节点的复杂架构图),Vue2的深层监听经常会导致页面卡顿,Vue3可以直接监听整个画布的对象或数组,不需要递归遍历,性能提升肉眼可见。
Composition API更灵活组织复杂逻辑
做流程图往往要写一堆逻辑:节点注册、事件监听、状态管理、导出功能……如果用Vue2的Options API,同一个功能的代码会被拆到data、methods、computed里,后期维护特别头疼,Vue3的Composition API可以用ref、reactive、computed这些组合式函数,把“画布缩放”“节点拖拽”“连边规则”这些功能封装成独立的hooks,比如useCanvasZoom、useNodeDrag,代码复用性和可读性都提升了不止一个档次。
Teleport组件解决了弹窗定位问题
专业的流程图一般会有节点属性配置弹窗,弹窗要么要浮在画布上不被遮挡,要么要挂载到body或者某个全局容器上,避免受父组件的overflow、z-index限制,Vue2实现这个要写额外的DOM操作代码,或者用第三方插件,Vue3自带的Teleport组件直接就能解决,只需要给弹窗加个to="body"属性就行,简单又安全。
Vue3做流程图应该选原生开发还是第三方组件库?
这是个非常关键的选择,直接影响开发周期和最终效果,我整理了两种方式的优劣势,大家可以根据自己的项目情况选:
原生开发的优劣势
原生开发就是自己用Canvas或者SVG写,不依赖第三方组件库。
- 优势:完全自由,想做什么功能就能做什么功能,比如可以定制独特的节点样式、特殊的连边算法、甚至是自定义的导出格式;没有额外的依赖包,项目体积会更小;性能完全可控,可以根据自己的需求优化渲染逻辑。
- 劣势:开发周期长,至少要花2-3周(如果是新手可能更长)才能做出一个基础的拖拽式流程图;技术门槛高,需要精通Canvas/SVG的API,还要懂一些计算机图形学的知识(比如碰撞检测、贝塞尔曲线绘制);后期维护成本高,每加一个功能都要自己写代码,没有现成的文档和社区支持。
- 适用场景:项目对流程图的功能、样式有非常特殊的要求,第三方组件库完全满足不了;团队有技术储备,有人精通Canvas/SVG和计算机图形学;项目周期充足。
第三方组件库的优劣势
现在市面上有很多成熟的Vue3流程图组件库,不用自己写底层逻辑,直接调用API就能实现大部分功能。
- 优势:开发周期短,基础功能(拖拽、缩放、连边、撤销重做、导出)1-2天就能搞定;技术门槛低,不需要精通Canvas/SVG的底层API,只需要看文档写配置;有现成的文档和社区支持,遇到问题可以查文档或者在GitHub/Stack Overflow上提问;后期维护成本低,组件库会持续更新bug和功能。
- 劣势:样式和功能有一定的限制,虽然可以自定义,但自由度不如原生开发;会增加项目的依赖包体积,一般成熟的流程图组件库体积在100KB-500KB之间;性能可能不如原生开发优化得好,但对于大部分项目(比如几百个节点以内的流程图)来说完全够用。
- 适用场景:项目对流程图的功能、样式没有非常特殊的要求;团队技术储备一般,没有精通Canvas/SVG的人;项目周期紧张。
市面上有哪些好用的Vue3流程图组件库?该怎么选?
我查了GitHub、npm和一些技术博客,选了4个比较火的Vue3流程图组件库,给大家做个对比:
LogicFlow
- 特点:蚂蚁金服开源的流程图组件库,主打“扩展性强”,核心代码用TypeScript写,对Vue3的支持非常好(有官方的@logicflow/vue3-adapter适配器);节点和连线都可以完全自定义,甚至可以用Vue组件当节点;内置了很多实用的功能,比如网格对齐、分组、节点/连线的右键菜单、撤销重做、导出SVG/PNG/JPEG/JSON;社区活跃,文档详细,有很多示例代码。
- 适用场景:企业级后台项目,比如业务流程图、架构图、ER图;需要用Vue组件自定义节点的项目;扩展性要求比较高的项目。
AntV X6
- 特点:阿里巴巴达摩院开源的图编辑引擎,不是专门的流程图组件库,但可以轻松实现流程图功能;同样用TypeScript写,对Vue3有官方适配器;核心功能比LogicFlow更强大,比如支持节点缩放、旋转、多画布、协同编辑(需要配合AntV XFlow);扩展性也很强,可以用React/Vue/Angular组件当节点;社区更活跃,用户量更大,文档更详细,示例代码更多。
- 适用场景:除了流程图,还需要做思维导图、拓扑图、BPMN图、UML图的项目;需要协同编辑功能的项目;对核心功能要求更高的项目。
Vue Flow
- 特点:专门为Vue3打造的轻量级流程图组件库,代码体积小(核心包只有几十KB);上手非常快,只需要几行代码就能实现一个基础的拖拽式流程图;节点和连线也可以自定义,但扩展性不如LogicFlow和X6;内置了网格对齐、缩放、撤销重做、导出JSON等基础功能;社区活跃,文档比较详细,有一些示例代码。
- 适用场景:个人项目或者小型企业项目,只需要基础流程图功能的项目;对项目体积要求比较高的项目。
GoJS
- 特点:老牌的商业图编辑组件库,不是开源的,需要付费使用;功能极其强大,几乎可以做任何类型的图;对Vue3有官方适配器;性能非常好,即使是几千个节点的复杂图也不会卡顿;文档极其详细,有几千个示例代码;有专业的技术支持。
- 适用场景:大型企业项目,对功能和性能要求极高的项目;预算充足的项目。
我最后选的是LogicFlow,因为公司项目只需要做业务流程图,不需要做其他类型的图,扩展性要求比较高,预算也有限,而且蚂蚁金服的开源项目质量一般都有保障。
用LogicFlow在Vue3项目中实现流程图的全流程步骤
下面我以LogicFlow为例,给大家详细讲一下从0到1实现一个供应链节点追踪流程图的步骤:
第一步:创建Vue3项目
如果你还没有Vue3项目,可以用Vite或者Vue CLI创建一个,我这里用Vite,因为Vite比Vue CLI快得多:
- 打开终端,输入
npm create vite@latest vue3-logicflow-demo -- --template vue-ts(如果不用TypeScript,可以把-- --template vue-ts去掉) - 进入项目目录,输入
cd vue3-logicflow-demo - 安装依赖,输入
npm install
第二步:安装LogicFlow的相关依赖
LogicFlow有核心包、Vue3适配器、主题包(可选),还有一些插件(比如右键菜单插件、分组插件、导出插件),我这里安装核心包、Vue3适配器、默认主题包、右键菜单插件、导出插件:
输入npm install @logicflow/core @logicflow/vue3-adapter @logicflow/theme @logicflow/extension --save
第三步:初始化LogicFlow画布
- 在src/components目录下创建一个新的组件,比如LogicFlowCanvas.vue
- 导入相关的依赖:
import { LogicFlow, type LFOptions } from '@logicflow/core' import { VueNodeView } from '@logicflow/vue3-adapter' import '@logicflow/theme' import { DndPanel, SelectionSelect, Menu, Snapshot } from '@logicflow/extension' import '@logicflow/extension/lib/style/index.css' - 在template中添加画布容器和拖拽面板容器:
<template> <div class="logic-flow-container"> <!-- 拖拽面板容器 --> <div class="dnd-panel" ref="dndPanelRef"></div> <!-- 画布容器 --> <div class="lf-container" ref="lfContainerRef"></div> </div> </template>
- 在script setup中初始化LogicFlow画布:
import { onMounted, ref } from 'vue'
// 定义画布容器和拖拽面板容器的引用 const lfContainerRef = ref<HTMLElement | null>(null) const dndPanelRef = ref<HTMLElement | null>(null) // 定义LogicFlow实例 let lf: LogicFlow | null = null
// 初始化LogicFlow const initLogicFlow = () => { if (!lfContainerRef.value) return
// 配置LogicFlow const options: LFOptions = { container: lfContainerRef.value, width: '100%', height: '100%', grid: { size: 20, // 网格大小 visible: true, // 是否显示网格 type: 'dot' // 网格类型(dot: 点, line: 线) }, background: { color: '#f5f5f5' // 背景颜色 }, plugins: [DndPanel, SelectionSelect, Menu, Snapshot] // 注册插件 }
// 创建LogicFlow实例 lf = new LogicFlow(options)
// 注册拖拽面板 const dndPanel = lf?.getPluginInstance('dnd-panel') as DndPanel dndPanel?.register({ type: 'rect', // 节点类型 label: '供应商', // 节点标签 icon: '📦' // 节点图标 }) dndPanel?.register({ type: 'circle', label: '仓库', icon: '🏭' }) dndPanel?.register({ type: 'diamond', label: '分拣中心', icon: '🚚' }) dndPanel?.register({ type: 'ellipse', label: '客户', icon: '👤' })
// 渲染画布 lf?.render() }
// 在组件挂载后初始化LogicFlow onMounted(() => { initLogicFlow() })
在style中添加样式:
```css
.logic-flow-container {
width: 100vw;
height: 100vh;
display: flex;
}
.dnd-panel {
width: 200px;
height: 100%;
background-color: #fff;
border-right: 1px solid #eee;
padding: 20px;
}
.lf-container {
flex: 1;
}
第四步:自定义节点和连线
现在我们已经有了一个基础的拖拽式流程图,但默认的节点和连线样式可能不符合产品经理的要求,我们可以自定义节点和连线的样式:
- 在src/components目录下创建一个新的文件夹,比如CustomNodes
- 在CustomNodes目录下创建一个新的组件,比如CustomRectNode.vue(自定义矩形节点):
<template> <div class="custom-rect-node" :style="{ backgroundColor: properties.color || '#409EFF' }"> <div class="custom-rect-node-icon">{{ properties.icon || '📦' }}</div> <div class="custom-rect-node-label">{{ properties.label || '节点' }}</div> </div> </template>
// 注册自定义节点 lf?.register({ type: 'custom-rect', // 自定义节点类型 view: VueNodeView, // 使用VueNodeView渲染 model: { props: { color: '#409EFF', // 默认颜色 icon: '📦', // 默认图标 label: '节点' // 默认标签 } }, component: CustomRectNode // 自定义Vue组件 })
在拖拽面板中使用自定义节点:
```typescript
dndPanel?.register({
type: 'custom-rect', // 自定义节点类型
label: '供应商',
icon: '' // 不需要默认图标了,因为自定义节点里已经有了
})
- 自定义连线的样式可以通过LF的style属性配置,比如把连线改成贝塞尔曲线,颜色改成#67C23A,宽度改成2px:
const options: LFOptions = { // 其他配置 style: { baseEdge: { stroke: '#67C23A', strokeWidth: 2, // 贝塞尔曲线 edgeType: 'bezier', // 贝塞尔曲线的控制参数 offset: 30 } }, // 其他配置 }
第五步:添加交互功能
现在我们的流程图已经有了自定义的节点和连线,但还需要一些实用的交互功能,比如节点属性配置、导出功能、撤销重做功能:
- 节点属性配置功能:可以用右键菜单插件和Vue的弹窗组件(比如Element Plus的ElDialog)实现,先在项目中安装Element Plus:
输入
npm install element-plus --save然后在main.ts中导入Element Plus:import { createApp } from 'vue' import './style.css' import App from './App.vue' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css'
const app = createApp(App) app.use(ElementPlus) app.mount('#app')
接着在LogicFlowCanvas.vue中添加右键菜单和节点属性配置弹窗:
```typescript
// 导入Element Plus的弹窗组件
import { ElDialog, ElForm, ElFormItem, ElInput, ElButton } from 'element-plus'
import { ref, reactive } from 'vue'
// 定义右键菜单配置
const menuConfig = {
nodeMenu: [
{
text: '配置属性',
callback: (node: any) => {
// 打开属性配置弹窗
currentNodeId.value = node.id
currentNodeProperties.value = { ...node.properties }
dialogVisible.value = true
}
},
{
text: '删除节点',
callback: (node: any) => {
lf?.deleteNode(node.id)
}
}
]
}
// 配置右键菜单
lf?.getPluginInstance('menu')?.setMenuConfig(menuConfig)
// 定义属性配置弹窗的状态
const dialogVisible = ref(false)
const currentNodeId = ref('')
const currentNodeProperties = reactive({
color: '#409EFF',
icon: '📦',
label: '节点'
})
// 保存节点属性
const saveNodeProperties = () => {
lf?.setProperties(currentNodeId.value, currentNodeProperties)
dialogVisible.value = false
}
然后在template中添加属性配置弹窗:
<template>
<!-- 其他代码 -->
<ElDialog v-model="dialogVisible" title="配置节点属性" width="400px">
<ElForm :model="currentNodeProperties" label-width="80px">
<ElFormItem label="节点颜色">
<ElInput v-model="currentNodeProperties.color" placeholder="请输入节点颜色(409EFF)" />
</ElFormItem>
<ElFormItem label="节点图标">
<ElInput v-model="currentNodeProperties.icon" placeholder="请输入节点图标()" />
</ElFormItem>
<ElFormItem label="节点标签">
<ElInput v-model="currentNodeProperties.label" placeholder="请输入节点标签" />
</ElFormItem>
</ElForm>
<template #footer>
<ElButton @click="dialogVisible = false">取消</ElButton>
<ElButton type="primary" @click="saveNodeProperties">保存</ElButton>
</template>
</ElDialog>
</template>
- 导出功能:可以用Snapshot插件实现,先在template中添加导出按钮:
<template> <!-- 其他代码 --> <div class="toolbar"> <ElButton type="primary" @click="exportSVG">导出SVG</ElButton> <ElButton type="success" @click="exportPNG">导出PNG</ElButton> <ElButton type="warning" @click="exportJSON">导出JSON</ElButton> <ElButton type="danger" @click="importJSON">导入JSON</ElButton> </div> </template>
然后在style中添加toolbar的样式:
.toolbar { position: absolute; top: 20px; right: 20px; display: flex; gap: 10px; z-index: 999; }接着在script setup中添加导出和导入的方法:
// 导入Element Plus的上传组件 import { ElUpload, type UploadFile, type UploadProps } from 'element-plus'
// 导出SVG const exportSVG = () => { const snapshot = lf?.getPluginInstance('snapshot') as Snapshot snapshot?.getSnapshot({ backgroundColor: '#f5f5f5', fileType: 'svg', fileName: '供应链节点追踪流程图' }) }
// 导出PNG const exportPNG = () => { const snapshot = lf?.getPluginInstance('snapshot') as Snapshot snapshot?.getSnapshot({ backgroundColor: '#f5f5f5', fileType: 'png', fileName: '供应链节点追踪流程图' }) }
// 导出JSON const exportJSON = () => { const data = lf?.getGraphData() const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = '供应链节点追踪流程图.json' a.click() URL.revokeObjectURL(url) }
// 导入JSON的文件读取方法 const handleFileChange: UploadProps['onChange'] = (file: UploadFile) => { const reader = new FileReader() reader.onload = (e) => { const data = JSON.parse(e.target?.result as string) lf?.render(data) } if (file.raw) { reader.readAsText(file.raw) } }
最后在template中添加上传组件:
```html
<template>
<!-- 其他代码 -->
<div class="toolbar">
<!-- 其他按钮 -->
<ElUpload
accept=".json"
:show-file-list="false"
:auto-upload="false"
:on-change="handleFileChange"
>
<ElButton type="info">导入JSON</ElButton>
</ElUpload>
</div>
</template>
- 撤销重做功能:Snapshot插件已经内置了撤销重做功能,只需要添加按钮调用就行,先在template中添加按钮:
<template> <!-- 其他代码 --> <div class="toolbar"> <!-- 其他按钮 --> <ElButton type="primary" @click="undo">撤销</ElButton> <ElButton type="success" @click="redo">重做</ElButton> </div> </template>
然后在script setup中添加撤销和重做的方法:
// 撤销 const undo = () => { const snapshot = lf?.getPluginInstance('snapshot') as Snapshot snapshot?.undo() }
// 重做 const redo = () => { const snapshot = lf?.getPluginInstance('snapshot') as Snapshot snapshot?.redo() }
### 第六步:测试和优化
现在我们的流程图已经基本完成了,接下来需要测试一下所有功能是否正常,比如拖拽节点、连边、配置属性、导出、导入、撤销重做,如果有问题可以查LogicFlow的官方文档或者在GitHub上提问,优化方面可以根据自己的项目情况调整,比如调整网格大小、背景颜色、节点样式、连线样式、工具栏的位置等等。
##
Vue3做流程图其实并不难,关键是要选对方式和工具——如果项目对功能、样式有非常特殊的要求,团队有技术储备,项目周期充足,可以选原生开发;否则建议选第三方组件库,比如LogicFlow、AntV X6、Vue Flow,其中LogicFlow比较适合企业级后台项目,上手也比较快。
今天的分享就到这里了,希望对大家有帮助,如果有什么问题可以在评论区留言,我会尽量回复大家。 版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网



