效果图:

最近项目开发时有一个流程图的功能,需要做流程节点的展示,就搜到了 Vue Flow 这个插件,这个插件总得来说还可以,简单已使用,下边就总结一下使用的方法:
Vue Flow官网:https://vueflow.dev/
1、安装插件:
| npm i --save @vue-flow/core |
复制
2、页面引入使用:
| <template> |
| <div style="width: 100%; height: 300px;"> |
| <VueFlow :nodes="nodes" :edges="edges" @node-click="onNodeClick" fit-view-on-init> |
| |
| <template #node-custom="nodeProps"> |
| <div>{{ nodeProps.data.label }}</div> |
| <div style="margin-top: 5px;">进度: {{ nodeProps.data.value }}%</div> |
| </template> |
| </VueFlow> |
| </div> |
| </template> |
| <script> |
| import { VueFlow } from '@vue-flow/core' |
| export default { |
| components: { |
| VueFlow |
| }, |
| data () { |
| return{ |
| |
| nodes: [ |
| |
| { id: '1', type: 'custom', data: { label: '金属制造冶炼', value: 30 }, position: { x: 300, y: 30 }, |
| style: { |
| width: '150px',height: '80px',padding: '15px', fontSize: '13px', |
| border: '2px solid #10D27A', borderRadius: '8px' |
| }, |
| }, |
| { id: '2',type: 'custom', data: { label: '金属镶边',value: 50 }, position: { x: 500, y: 30 }, |
| style: { |
| width: '150px',height: '80px',padding: '15px', fontSize: '13px', |
| border: '2px solid #F1881C', borderRadius: '8px' |
| }, |
| }, |
| { id: '3',type: 'custom', data: { label: '整形', value: 80 }, position: { x: 400, y: 150 }, |
| style: { |
| width: '150px',height: '80px',padding: '15px', fontSize: '13px', |
| border: '2px solid #81D85D', borderRadius: '8px' |
| }, |
| }, |
| { id: '4',type: 'custom', data: { label: '冲洗', value: 40 }, position: { x: 400, y: 250 }, |
| style: { |
| width: '150px',height: '80px',padding: '15px', fontSize: '13px', |
| border: '2px solid #0F6DC6', borderRadius: '8px' |
| }, |
| }, |
| ], |
| |
| edges: [ |
| { id: 'e1-1', source: '1', target: '3'}, |
| { id: 'e1-2', source: '2', target: '3' }, |
| { id: 'e1-3', source: '3', target: '4' }, |
| ], |
| } |
| }, |
| created() { |
| |
| }, |
| mounted() { |
| |
| }, |
| methods: { |
| |
| onNodeClick(node) { |
| console.log('Node clicked:', node); |
| }, |
| } |
| } |
| |
| </script> |
| <style> |
| |
| @import "@vue-flow/core/dist/style.css"; |
| |
| @import "@vue-flow/core/dist/theme-default.css"; |
| </style> |
复制
解析:
- nodes里边的data数据可以自定义配置,但需要设置 type: 'custom',

附加1:上图是从左到右展示的,如果需要修改方向,方法如下:
| <div style="width: 100%; height: 200px;"> |
| <VueFlow :nodes="newNodes" :edges="newEdges" @node-click="onNodeClick" fit-view-on-init> |
| |
| <template #node-custom="nodeProps"> |
| |
| <Handle type="source" position="right" /> |
| <div>{{ nodeProps.data.label }}</div> |
| <div style="margin-top: 5px;">进度: {{ nodeProps.data.value }}%</div> |
| |
| <Handle type="target" position="left" :connectable="false" /> |
| </template> |
| </VueFlow> |
| </div> |
复制
附加2:假如展示流程图的时候不知道节点坐标,而后端又没有给,那么这个时候就需要自己去动态生成,方法如下:
| |
| mounted() { |
| this.calculateNodePositions(); |
| this.newNodes = this.nodes; |
| this.newEdges = this.edges; |
| }, |
| methods: { |
| |
| calculateNodePositions() { |
| const positionMap = {}; |
| const processedNodes = new Set(); |
| let yPosition = 100; |
| |
| this.edges.forEach(edge => { |
| |
| const sourceNode = this.nodes.find(node => node.id === edge.source); |
| const targetNode = this.nodes.find(node => node.id === edge.target); |
| |
| if (!processedNodes.has(edge.source)) { |
| positionMap[edge.source] = { x: 100, y: yPosition }; |
| yPosition += 100; |
| processedNodes.add(edge.source); |
| } |
| |
| const sourcePosition = positionMap[edge.source]; |
| if (sourcePosition && !processedNodes.has(edge.target)) { |
| |
| positionMap[edge.target] = { |
| x: sourcePosition.x + 200, |
| y: sourcePosition.y + 50 |
| }; |
| processedNodes.add(edge.target); |
| } |
| }); |
| |
| this.nodes.forEach(node => { |
| if (positionMap[node.id]) { |
| node.position = positionMap[node.id]; |
| } |
| }); |
| }, |
| } |
复制
3、更多配置项:
3.1、节点点击事件
| <!--绑定--> |
| <VueFlow :nodes="nodes" :edges="edges" @node-click="onNodeClick" /> |
| |
| |
| onNodeClick(node) { |
| console.log('Node clicked:', node); |
| }, |
复制
3.2、节点拖拽事件
| <!--绑定--> |
| <VueFlow :nodes="nodes" :edges="edges" @node-drag="onNodeDrag" /> |
| |
| |
| onNodeDrag({ node, position }) { |
| console.log('Node dragged:', node.id, 'New position:', position); |
| }, |
| |
复制
3.3、连接边事件
| <!--绑定--> |
| <VueFlow :nodes="nodes" :edges="edges" @connect="onConnect" /> |
| |
| |
| onConnect(edge) { |
| console.log('Edge connected:', edge); |
| }, |
| |
| |
复制
3.4、节点双击事件
| <!--绑定--> |
| <VueFlow :nodes="nodes" :edges="edges" @node-dblclick="onNodeDoubleClick" /> |
| |
| |
| onNodeDoubleClick(node) { |
| console.log('Node double clicked:', node); |
| }, |
| |
| |
| |
复制
3.5、画布缩放和拖动事件
| <!--绑定--> |
| <VueFlow :nodes="nodes" :edges="edges" @zoom-change="onZoomChange" @canvas-click="onCanvasClick" /> |
| |
| |
| onZoomChange(event) { |
| console.log('Zoom changed:', event); |
| }, |
| onCanvasClick(event) { |
| console.log('Canvas clicked:', event); |
| }, |
| |
| |
| |
| |
复制
4、常用节点连接线样式示例
4.1、普通直线
| const edges = [ |
| { id: 'e1-1', source: '1', target: '2', style: { stroke: '#10D27A', strokeWidth: 2 } }, |
| ]; |
复制
4.2、虚线
| const edges = [ |
| { id: 'e1-1', source: '1', target: '2', style: { stroke: '#F1881C', strokeWidth: 2, strokeDasharray: '5,5' } }, |
| ]; |
复制
4.3、带箭头
| const edges = [ |
| { id: 'e1-1', source: '1', target: '2', |
| style: { stroke: '#4682b4', strokeWidth: 2, markerEnd: 'url(#arrow)', }, |
| }, |
| ]; |
| |
复制
4.4、带圆角
| const edges = [ |
| { id: 'e1-1', source: '1', target: '2', style: { stroke: '#FF6347', strokeWidth: 4, strokeLinecap: 'round' } }, |
| ]; |
| |
复制
4.5、自定义边颜色和宽度
| const edges = [ |
| { id: 'e1-1', source: '1', target: '2', style: { stroke: '#000', strokeWidth: 6 } }, |
| { id: 'e1-2', source: '2', target: '3', style: { stroke: '#FF0000', strokeWidth: 3 } }, |
| ]; |
| |
| |
复制
4.6、带动效的连接线
| const edges = [ |
| { id: 'e1-1', source: '1', target: '2, animated: true,}, |
| ]; |
| |
| |
| |
复制
至此完成!!!
测试有效!!!感谢支持!!!