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
待續。。。