文章目录
- 一、项目简介
- 二、流程图基础结构搭建
- 2.1 安装依赖
- 2.2 基础组件结构
- 三、节点拖拽与连接逻辑
- 3.1 拖拽添加节点
- 3.2 jsPlumb 初始化与连接规则
- 四、节点图标与颜色选择功能
- 4.1 节点数据结构
- 4.2 图标与颜色右键菜单
- 4.3 渲染节点样式
- 五、节点与连线删除功能
- 5.1 快捷键删除
- 5.2 删除连线
- 六、导入导出 JSON 数据
- 6.1 导出结构
- 6.2 导入结构
- 七、视图缩放与自动居中
- 八、自动布局拓展方向
- 九、组件封装建议
一、项目简介
本文基于 Vue 3 + jsPlumb 实现一个完整的流程图组件,具备以下功能:
- 支持节点拖拽添加
- 支持节点之间连接与删除
- 节点支持自定义图标与颜色选择
- 支持导入导出 JSON 数据
- 支持视图缩放与自动居中
- 支持快捷键删除、右键菜单操作
- 支持自动布局拓展
- 具备组件封装能力,可复用
二、流程图基础结构搭建
2.1 安装依赖
npm install jsplumb
2.2 基础组件结构
<template><div class="flow-container" ref="container"><divv-for="node in nodes":key="node.id"class="flow-node":id="node.id":style="getNodeStyle(node)"@contextmenu.prevent="showContextMenu(node, $event)"><div class="icon">{{ node.icon }}</div><div class="label">{{ node.label }}</div></div><context-menuv-if="context.visible":node="context.node":x="context.x":y="context.y"@update="updateNode"@delete="deleteNode"/></div>
</template>
三、节点拖拽与连接逻辑
3.1 拖拽添加节点
function addNode(label = '新节点') {const id = 'node-' + Date.now();nodes.value.push({id,label,icon: '📦',color: '#409EFF',left: 200,top: 150});nextTick(() => {instance.value.draggable(id, { containment: 'parent' });initEndpoints(id);});
}
3.2 jsPlumb 初始化与连接规则
onMounted(() => {instance.value = jsPlumb.getInstance();instance.value.bind('connection', info => {connections.value.push({source: info.sourceId,target: info.targetId});});nodes.value.forEach(node => {instance.value.draggable(node.id, { containment: 'parent' });initEndpoints(node.id);});
});function initEndpoints(id) {instance.value.addEndpoint(id, {anchor: 'Right',isSource: true,maxConnections: -1}, commonStyle);instance.value.addEndpoint(id, {anchor: 'Left',isTarget: true,maxConnections: -1}, commonStyle);
}
四、节点图标与颜色选择功能
4.1 节点数据结构
{id: 'node-1',label: '开始',icon: '🟢',color: '#67C23A',left: 100,top: 100
}
4.2 图标与颜色右键菜单
<!-- ContextMenu.vue -->
<template><div class="context-menu" :style="{ left: x + 'px', top: y + 'px' }"><label>名称:<input v-model="node.label" /></label><label>图标:<select v-model="node.icon"><option>📦</option><option>🟢</option><option>📄</option><option>🔴</option></select></label><label>颜色:<input type="color" v-model="node.color" /></label><button @click="$emit('delete', node)">删除节点</button></div>
</template>
4.3 渲染节点样式
function getNodeStyle(node) {return {left: node.left + 'px',top: node.top + 'px',backgroundColor: node.color};
}
五、节点与连线删除功能
5.1 快捷键删除
window.addEventListener('keydown', e => {if (e.key === 'Delete' && selectedNode.value) {deleteNode(selectedNode.value);}
});
5.2 删除连线
instance.value.bind('click', conn => {instance.value.deleteConnection(conn);connections.value = connections.value.filter(c => !(c.source === conn.sourceId && c.target === conn.targetId));
});
六、导入导出 JSON 数据
6.1 导出结构
function exportFlow() {const data = {nodes: nodes.value,connections: connections.value};const json = JSON.stringify(data, null, 2);console.log(json);
}
6.2 导入结构
function importFlow(json) {const data = JSON.parse(json);nodes.value = data.nodes;connections.value = data.connections;nextTick(() => {nodes.value.forEach(n => {instance.value.draggable(n.id, { containment: 'parent' });initEndpoints(n.id);});connections.value.forEach(conn => {instance.value.connect({source: conn.source,target: conn.target});});});
}
七、视图缩放与自动居中
function zoomView(scale) {const container = document.querySelector('.flow-container');container.style.transform = `scale(${scale})`;container.style.transformOrigin = '0 0';
}function centerView() {const container = document.querySelector('.flow-container');container.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
八、自动布局拓展方向
可借助 dagre.js 或 elkjs 实现自动布局:
- 自动计算节点位置
- 优化连接路径
- 支持有向图/流程图布局模式
npm install dagre
九、组件封装建议
- 封装为
<FlowEditor />
组件 - 支持
v-model:data
传入节点与连线数据 - 提供
@save
、@connect
、@delete
等事件钩子 - 可组合使用多个视图与工具栏
到这里,这篇文章就和大家说再见啦!我的主页里还藏着很多 篇 前端 实战干货,感兴趣的话可以点击头像看看,说不定能找到你需要的解决方案~
创作这篇内容花了很多的功夫。如果它帮你解决了问题,或者带来了启发,欢迎:
点个赞❤️ 让更多人看到优质内容
关注「前端极客探险家」🚀 每周解锁新技巧
收藏文章⭐️ 方便随时查阅
📢 特别提醒:
转载请注明原文链接,商业合作请私信联系
感谢你的阅读!我们下篇文章再见~ 💕