bpmn-js + vue实现工作流设计器
此文只为记录一下自己学习bpmn-js和使用bpmn-js实现工作流设计器的过程。以后我将通过不断提出新需求的方式,来逐渐完成一个简单的工作流设计器。
1、bpmn-js初体验
安装vue
新版的vue-cli有图形化工具,新版本的Vue CLI 的包名称由 vue-cli 改成了 @vue/cli。如果你已经全局安装了旧版本的 vue-cli (1.x 或 2.x),你需要先通过 npm uninstall vue-cli -g进行卸载
# 新版安装命令
npm install -g @vue/cli
# 安装完成后,我们就可以使用vue ui命令打开图形界面来创建管理vue项目了
vue ui
使用vue-cli创建项目
略…
安装bpmn-js
# 切换到新建的项目
npm install bpmn-js --save-dev
按装完成后可以在node-modules中找到这几个文件夹
简单的查看工作流图形的例子
官方的例子都是基于jquery的,在获取bpmn20.xml文档的时候可以直接import,在vue中需要通过异步请求来获取数据,因此需要安装axios
- 安装axios
npm install axios
- 安装完成以后修改main.js
- 添加一个vue组件,直接上代码
<template>
<div class="containers">
<div id="canvas" class="canvas" ref="canvas"></div>
</div>
</template>
<script>
import BpmnJS from 'bpmn-js' // 引入 bpmn-js
export default {
data () {
},
mounted() {
var viewer = new BpmnJS({
container: '#canvas'
})
var diagramUrl = 'https://cdn.staticaly.com/gh/bpmn-io/bpmn-js-examples/dfceecba/starter/diagram.bpmn';
// var diagramUrl = 'http://localhost:8080/pizza-collaboration.bpmn20.xml';
this.$http.get(diagramUrl)
.then(function(res){
viewer.importXML(res.data, function(err){
if (!err) {
console.log('success!')
viewer.get('canvas').zoom('fit-viewport')
console.log('success...')
} else {
console.log('something went wrong:', err)
}
})
})
.catch(function(err){
console.log(err)
})
}
}
</script>
<style lang="scss">
/*左边工具栏以及编辑节点的样式*/
@import '~bpmn-js/dist/assets/diagram-js.css';
@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
.containers{
position: absolute;
background-color: #ffffff;
width: 100%;
height: 100%;
.canvas{
width: 100%;
height: 100%;
}
.bjs-powered-by {
display: none;
}
}
</style>
运行以后可以看到一下页面
使用中间遇到的问题
- 图形不显示,F12 发现报错
something went wrong: Error: unparsable content omgdc:Bounds detected; this may indicate an invalid BPMN 2.0 diagram file
line: 0
column: 4310
nested error: missing namespace on omgdc:Bounds
at error (index.esm.js?42c7:63)
at handleError (index.esm.js?42c7:689)
at handleError (index.esm.js?ea8d:193)
at parse (index.esm.js?ea8d:1016)
at Parser.parse (index.esm.js?ea8d:298)
at eval (index.esm.js?42c7:856)
非常郁闷,我的bpmn文件命名都指明了namespace,为什么还提示 missing namespace?
viewer#importXML需要的参数是个字符串,所以想当然的将res转化为字符串,后来 仔细查看res中的数据发现res是一个object,res = {data:""} ,所以只需需要取出data就可以了。
解决:
2、新需求:可以拖拽自定义工作流
实现工作流的编辑需要用到bpmn-js的另一个重要的组件(BpmnModeler)。
效果: 这里顺便测试了国际化
还是直接上代码
<template>
<div class="containers" ref="containers">
<div id="js-canvas" class="canvas" ref="canvas"></div>
</div>
</template>
<script>
// 引入Modeler
import BpmnModeler from 'bpmn-js/lib/Modeler' // 引入 bpmn-js
// 用来进行国际化,参考官方的例子 bpmn-js-examples-master ===> i18n
import customTranslate from '../customTranslate/customTranslate';
export default {
data () {
return {
bpmnModeler: null,
containers: null,
canvas: null,
customTranslateModule: {
translate: [ 'value', customTranslate ]
}
}
},
methods:{
openDiagram(xml){
this.bpmnModeler.importXML(xml, function(err) {
if (err) {
// container
// .removeClass('with-diagram')
// .addClass('with-error');
console.error(err);
} else {
// container
// .removeClass('with-error')
// .addClass('with-diagram');
}
});
},
// 注意:必须先加载一个bpmn文件,新建就是加载一个空的bpmn文件,否则不能拖拽节点
createNewDiagram(){
//var diagramUrl = 'https://cdn.staticaly.com/gh/bpmn-io/bpmn-js-examples/dfceecba/starter/diagram.bpmn';
// var diagramUrl = 'http://localhost:8080/newDiagram.bpmn';
this.$http.get(diagramUrl)
// 这里必须使用箭头函数,否则提示找不到openDiagram方法
.then((res)=>{
console.log(res.data)
this.openDiagram(res.data)
})
.catch((err)=>{
console.log(err)
})
},
},
mounted() {
// 获取到属性ref为“containers”的dom节点
this.containers = this.$refs.containers
console.log(this.customTranslate)
// 获取到属性ref为“canvas”的dom节点
const canvas = this.$refs.canvas
this.bpmnModeler = new BpmnModeler({
container: canvas,
additionalModules: [
this.$data.customTranslateModule
]
})
this.createNewDiagram()
}
}
</script>
<style lang="scss">
/*左边工具栏以及编辑节点的样式*/
@import '~bpmn-js/dist/assets/diagram-js.css';
@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
@import '~bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
.containers{
position: absolute;
background-color: #ffffff;
width: 100%;
height: 100%;
.canvas{
width: 100%;
height: 100%;
}
.bjs-powered-by {
display: none;
}
}
</style>
碰到的问题:
- 找不到openDiagram方法: 开始的时候在axios#get#then方法中使用匿名函数作为回调函数,这个问题主要是由于this这个对象指向引起的. 改成箭头函数,问题解决。
- axios中的this的指向:
匿名函数的指针指向->函数操作的本身
箭头函数的指针指向->组件
也就是说当你需要使用到组件中声明的变量或者函数,就需要使用箭头函数
简单记录一下匿名函数和箭头函数中this的指向:
- 匿名函数:
在一般情况下,this对象时在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。但是,匿名函数的执行环境具有全局性,因此它的this对象通常指向windows.
- 箭头函数:
(1)默认指向定义它时,所处上下文的对象的this指向。即ES6箭头函数里this的指向就是上下文里对象this指向,偶尔没有上下文对象,this就指向window
(2)即使是call,apply,bind等方法也不能改变箭头函数this的指向
3、新需求:添加属性面板
属性面板需要单独安装
npm install --save bpmn-js-properties-panel
npm install --save camunda-bpmn-moddle
待续。。。