在当今信息化社会,流程图已成为表达业务逻辑、工作流程以及数据处理路径等复杂系统的不可或缺的工具。随着前端技术的不断发展,Web 端流程图的可视化展示需求也日益增长。在这样的背景下,Vue.js 和 bpmn.js 的结合,为开发者提供了一个高效、灵活且易于维护的解决方案,用于在 Web 应用中实现XML流程图的渲染与展示。
本文将详细介绍如何在 Vue 应用中使用 bpmn.js 实现 XML 流程图的渲染展示,包括环境搭建、基本用法、高级特性以及优化技巧等方面。
需要依赖
npm install bpmn-js --save
// 如果想要从本地导入bpmn格式的流程文件,需要配置 raw-loader
npm install raw-loader --save
// 用来实现拖动功能
npm i diagram-js --save
自定义拖拽 custom-bpmn.js
bpmn-js 的 Viewer 模式,默认情况下,并不具备拖动功能,这意味着用户不能通过直接操作界面上的元素来实现位置的调整。
然而,bpmn-js 提供了 diagram-js 插件,这一插件可以弥补 Viewer 模式在拖动功能上的不足。为了满足用户的实际需求,我们可以自定义的 Viewer—— custom-bpmn.js,这个Viewer内置了拖动功能,使得用户能够轻松地对界面上的元素进行拖拽操作。
import inherits from 'inherits'
import Viewer from 'bpmn-js/lib/Viewer'
import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll'
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'
function CustomViewer (options) {
Viewer.call(this, options)
}
inherits(CustomViewer, Viewer)
CustomViewer.prototype._modules = [].concat(Viewer.prototype._modules, [
ZoomScrollModule,
MoveCanvasModule
])
export { CustomViewer }
在使用时,用户只需简单地引入 custom-bpmn,即可享受到这一便捷功能,无需进行额外的配置或操作。通过 custom-bpmn,用户能够更加灵活地操作 bpmn-j s的 Viewer 模式,实现更加高效的流程设计和编辑。
基本组件
在需要进行渲染时,您无需手动打开或加载文件,而是可以直接调用 bpmn-js 库中的 importXML 函数,并将 xmlStr 变量作为参数传递给它。importXML 函数会解析 xmlStr 中的 XML 内容,并将其转化为可视化的流程图。
<template>
<div class="containers">
<div class="canvas" ref="canvas" style="height: 60vh;background: white"></div>
</div>
</template>
<script>
// 数据请求
import { getXML } from '@/api/getXML'
// 引入自定义 Viewer
import {CustomViewer} from '@/util/custom-bpmn.js'
export default {
name: "bpmnViewer",
mounted() {
this.init();
},
data() {
return {
bpmnViewer: null,
container: null,
canvas: null
};
},
methods: {
init () {
const canvas = this.$refs.canvas
this.bpmnViewer = new CustomViewer({
container: canvas
})
this.createNewDiagram()
},
async createNewDiagram() {
try {
// 第一种,本地 .bpmn 文件地址
const bpmnXml = require('@/bpmns/test.bpmn')
const result = await this.bpmnViewer.importXML(bpmnXml.default)
const { warnings } = result;
console.log(warnings);
// 第二种,请求接口获取 XML 文件流
await getXML({ xmlID: this.xmlID }).then(res => {
const result = this.bpmnViewer.importXML(res.data.xml)
const { warnings } = result;
console.log(warnings);
})
this.addMarker()
} catch (err) {
console.log(err.message, err.warnings);
}
}
}
};
</script>
模拟用的 test.bpmn 文件
除了利用本地保存的 bpmn 格式流程文件,bpmn-js 库还提供了另一种灵活的方式来加载和展示流程图。您可以将 bpmn 流程图的内容以字符串的形式存储在一个变量中,例如命名为 xmlStr。这个字符串变量包含了完整的 bpmn XML 代码,详细描述了流程图的各个元素及其属性。
<?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:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2" targetNamespace="http://bpmn.io/bpmn" exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="5.1.2">
<process id="Process_1" isExecutable="false">
<startEvent id="StartEvent_ops_coffee" name="开始">
<outgoing>Flow_0jfbnmb</outgoing>
</startEvent>
<sequenceFlow id="Flow_0jfbnmb" sourceRef="StartEvent_ops_coffee" targetRef="Activity_0pih3d0" />
<task id="Activity_0pih3d0" name="流程1">
<incoming>Flow_0jfbnmb</incoming>
<outgoing>Flow_0ow8zy1</outgoing>
</task>
<task id="Activity_07b4aeg" name="流程2">
<incoming>Flow_0ow8zy1</incoming>
<outgoing>Flow_0iaccmi</outgoing>
</task>
<sequenceFlow id="Flow_0ow8zy1" sourceRef="Activity_0pih3d0" targetRef="Activity_07b4aeg" />
<task id="Activity_11xlozw" name="流程3">
<incoming>Flow_0iaccmi</incoming>
<outgoing>Flow_0bax3n1</outgoing>
</task>
<sequenceFlow id="Flow_0iaccmi" sourceRef="Activity_07b4aeg" targetRef="Activity_11xlozw" />
<sequenceFlow id="Flow_0bax3n1" sourceRef="Activity_11xlozw" targetRef="Event_07dyz8d" />
<endEvent id="Event_07dyz8d" name="結束">
<incoming>Flow_0bax3n1</incoming>
</endEvent>
</process>
<bpmndi:BPMNDiagram id="BpmnDiagram_1">
<bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNEdge id="Flow_0jfbnmb_di" bpmnElement="Flow_0jfbnmb">
<omgdi:waypoint x="188" y="120" />
<omgdi:waypoint x="300" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0ow8zy1_di" bpmnElement="Flow_0ow8zy1">
<omgdi:waypoint x="400" y="120" />
<omgdi:waypoint x="530" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0iaccmi_di" bpmnElement="Flow_0iaccmi">
<omgdi:waypoint x="630" y="120" />
<omgdi:waypoint x="780" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0bax3n1_di" bpmnElement="Flow_0bax3n1">
<omgdi:waypoint x="880" y="120" />
<omgdi:waypoint x="1032" y="120" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="StartEvent_1y45yut_di" bpmnElement="StartEvent_ops_coffee">
<omgdc:Bounds x="152" y="102" width="36" height="36" />
<bpmndi:BPMNLabel>
<omgdc:Bounds x="159" y="153" width="22" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0pih3d0_di" bpmnElement="Activity_0pih3d0">
<omgdc:Bounds x="300" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_11xlozw_di" bpmnElement="Activity_11xlozw">
<omgdc:Bounds x="780" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_07b4aeg_di" bpmnElement="Activity_07b4aeg">
<omgdc:Bounds x="530" y="80" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_07dyz8d_di" bpmnElement="Event_07dyz8d">
<omgdc:Bounds x="1032" y="102" width="36" height="36" />
<bpmndi:BPMNLabel>
<omgdc:Bounds x="1039" y="145" width="22" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>