ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

React+bpmn.js实现基本流程图(一)

2026/8/15 15:58:04 拓冰建站 浏览量
React+bpmn.js实现基本流程图(一)

效果如图:

项目背景

最近的项目使用的React,需要用到bpmn-js来设计流程图。项目中使用的各插件版本

//package.json { "react": ">=18.0.0", "react-dom": ">=18.0.0", "bpmn-js": "^18.8.0", "antd": "^5.0.0", "less": "^4.5.1", "less-loader": "^7.0.0" }

我用的React v18版本,低于18版本的自行修改React语法

bpmn-js基础使用示例

1. 安装依赖

npm install bpmn-js

2. 创建BPMN组件

2.1 基本组件 /BpmnModelerWidget/index.tsx

import React, { useEffect, useRef, useState } from 'react'; import BpmnModeler from 'bpmn-js/lib/Modeler'; import 'bpmn-js/dist/assets/diagram-js.css'; import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'; import 'bpmn-js/dist/assets/bpmn-js.css'; import { defXmlStr } from "./xmlStr"; import './styles.less' const BpmnModelerWidget = ({ initialXml, onSave }) => { const containerRef = useRef(null); const modelerRef = useRef(null); const [xml, setXml] = useState(''); const [error, setError] = useState(null); useEffect(() => { // 初始化建模器 modelerRef.current = new BpmnModeler({ container: containerRef.current }); // 加载初始XML if (initialXml) { loadDiagram(initialXml); } else { createNewDiagram(); } // 监听变化 modelerRef.current.on('commandStack.changed', async () => { try { const { xml: newXml } = await modelerRef.current.saveXML({ format: true }); setXml(newXml); } catch (err) { console.error('Failed to save XML', err); } }); return () => { modelerRef.current?.destroy(); }; }, []); const loadDiagram = async (xml) => { try { await modelerRef.current.importXML(xml); const canvas = modelerRef.current.get('canvas'); canvas.zoom('fit-viewport'); setError(null); } catch (err) { setError('Failed to load diagram'); console.error(err); } }; const createNewDiagram = async () => { const newDiagram = defXmlStr('New_Process', 'New Process') await loadDiagram(newDiagram); }; const handleImport = async (event) => { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = async (e) => { const xml = e.target.result; try { await modelerRef.current.importXML(xml); } catch (err) { console.error('Failed to import diagram:', err); } }; reader.readAsText(file); } }; const handleSave = async () => { try { const { xml: savedXml } = await modelerRef.current.saveXML({ format: true }); if (onSave) { onSave(savedXml); } } catch (err) { console.error('Failed to save', err); } }; const handleExportBPMN = async () => { try { const { xml } = await modelerRef.current.saveXML({ format: true }); const blob = new Blob([xml], { type: 'application/xml' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'diagram.bpmn'; a.click(); URL.revokeObjectURL(url); } catch (err) { console.error('Failed to export diagram:', err); } } const handleExportSVG = async () => { try { const { svg } = await modelerRef.current.saveSVG(); const blob = new Blob([svg], { type: 'image/svg+xml' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'diagram.svg'; a.click(); URL.revokeObjectURL(url); } catch (err) { console.error('Failed to export SVG', err); } }; return ( <div className="bpmn-modeler"> {error && <div className="error">{error}</div>} <div className="toolbar"> <button onClick={createNewDiagram}>新建</button> <input type="file" accept=".bpmn" onChange={handleImport} /> <button onClick={handleSave}>保存</button> <button onClick={handleExportBPMN}>导出BPMN</button> <button onClick={handleExportSVG}>导出SVG</button> </div> <div id='canvas' className='modeler-container' ref={containerRef} /> </div> ); }; export default BpmnModelerWidget;

2.2 默认字符串 /BpmnModelerWidget/xmlStr.tsx

/** * bpmn默认字符串 * @param flowKey 流程标识 * @param flowName 流程名称 * @returns 默认的xml:只包含开始节点 */ export const defXmlStr = (flowKey?: string, flowName?: string) => `<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" targetNamespace="http://bpmn.io/schema/bpmn"> <process id="${flowKey}" name="${flowName}" isExecutable="true"> <startEvent id="Event_0m4asyn" /> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_1"> <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="${flowKey}"> <bpmndi:BPMNShape id="Event_0m4asyn_di" bpmnElement="Event_0m4asyn"> <dc:Bounds x="232" y="182" width="36" height="36" /> </bpmndi:BPMNShape> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>`;

2.3 样式文件 /BpmnModelerWidget/styles.less

.bpmn-modeler { height: 100%; position: relative; .toolbar { position: absolute; bottom: 10px; left: 10px; z-index: 2; button { cursor: pointer; margin: 0 5px; } input { width: 76px; } } .modeler-container { width: 100%; height: 100%; background: #fdf5eb; .bjs-container { /* 圆点背景 */ background: radial-gradient(circle at 0.5px 0.5px, #999 0.5px, transparent 0); background-size: 10px 10px; //圆点间隔(自定义值) 第一值是左右间隔 第二个值是上下间隔 } } }

这样就完成了一个基本的流程设计器,后续使用过程中会记录更多的使用功能。

代码仓库

完整代码已上传至 https://gitee.com/z-beast/bpmn-logic-flowchart