前言
Q: bpmn.js是什么? ???
bpmn.js是一個BPMN2.0渲染工具包和web建模器, 使得畫流程圖的功能在前端來完成.
Q: 我為什么要寫該系列的教材? ???
因為公司業(yè)務(wù)的需要因而要在項目中使用到bpmn.js,但是由于bpmn.js的開發(fā)者是國外友人, 因此國內(nèi)對這方面的教材很少, 也沒有詳細(xì)的文檔. 所以很多使用方式很多坑都得自己去找.在將其琢磨完之后, 決定寫一系列關(guān)于它的教材來幫助更多bpmn.js的使用者或者是期于找到一種好的繪制流程圖的開發(fā)者. 同時也是自己對其的一種鞏固.
由于是系列的文章, 所以更新的可能會比較頻繁, 您要是無意間刷到了且不是您所需要的還請諒解??.
不求贊??不求心??. 只希望能對你有一點(diǎn)小小的幫助.
所有教材的github地址: 《bpmn-chinese-document》
http請求篇
上一章節(jié)我們介紹了bpmn.js的一些基礎(chǔ)知識點(diǎn)以及介紹了在vue是如何使用的, 要是對bpmn.js不了解的小伙請移步:
這一章節(jié)主要講解的是關(guān)于bpmn.js如何與后臺進(jìn)行交互的問題, 通過學(xué)習(xí)此章節(jié)你可以學(xué)習(xí)到:
通過http請求獲取數(shù)據(jù)并渲染
在之前的案例中使用的一直都是本地寫死的一個xml字符串, 那么實際使用上肯定不會以這種方式.
我們團(tuán)隊現(xiàn)在采用的做法是:
- 前端發(fā)起請求, 獲取到一個
bpmn文件的地址 - 拿到地址之后, 使用
axios請求這個地址得到xml的字符串(這里命名為bpmnXmlStr) - 使用
importXML方法將字符串轉(zhuǎn)化為圖形并渲染.
為了模擬上面的執(zhí)行環(huán)境我接著上一章節(jié)的項目案例bpmn-vue-basic在components文件夾下創(chuàng)建一個axios.vue的 文件并配置好路由:
const routes = [
...
{
path: '/axios',
component: () => import('./../components/axios')
}
]
同時在項目中安裝axios以用于前端發(fā)送http請求:
npm i axios --save-D
首先在HTML代碼中作出一個loading的效果, 用戶前端在獲取到xml之前的一個展示:
// axios.vue
<template>
<div class="containers">
<div class="loading" v-if="loading">
Loading...
</div>
<template v-else>
<div class="canvas" ref="canvas"></div>
<div id="js-properties-panel" class="panel"></div>
</template>
</div>
</template>
然后在js中引入axios并定義一個getXmlUrl方法模擬獲取bpmn文件地址:
// axios.vue
<script>
...
import axios from 'axios'
import { xmlStr } from '../mock/xmlStr' // 引入一個本地的xml字符串, 若是沒有獲取到后臺的數(shù)據(jù)則用它
export default {
...
data () {
return {
...
loading: true,
xmlUrl: '',
defaultXmlStr: xmlStr
}
},
methods: {
async init () {
this.loading = true
this.xmlUrl = await this.getXmlUrl()
console.log(this.xmlUrl)
this.loading = false
this.$nextTick(() => { // 等待 DOM 更新之后再對工作流進(jìn)行初始化
this.initBpmn()
})
},
getXmlUrl () { // 該方法模擬請求后臺獲取bpmn文件地址
return new Promise(resolve => {
setTimeout(() => {
const url = 'https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/bpmnMock.bpmn' // 模擬網(wǎng)絡(luò)請求的一個地址
resolve(url)
}, 1000)
})
},
initBpmn () {
... // 這里是初始化工作流的代碼
this.createNewDiagram()
},
async createNewDiagram () {
const that = this
let bpmnXmlStr = ''
if (this.xmlUrl === '') { // 若是后臺沒有數(shù)據(jù)則使用默認(rèn)的一個xml
bpmnXmlStr = this.defaultXmlStr
this.transformCanvas(bpmnXmlStr)
} else {
let res = await axios({
method: 'get',
timeout: 120000,
url: that.xmlUrl,
headers: { 'Content-Type': 'multipart/form-data' }
})
console.log(res)
bpmnXmlStr = res['data']
this.transformCanvas(bpmnXmlStr)
}
},
transformCanvas(bpmnXmlStr) {
// 將字符串轉(zhuǎn)換成圖顯示出來
this.bpmnModeler.importXML(bpmnXmlStr, (err) => {
if (err) {
console.error(err)
} else {
this.success()
}
// 讓圖能自適應(yīng)屏幕
var canvas = this.bpmnModeler.get('canvas')
canvas.zoom('fit-viewport')
})
},
success () {
console.log('創(chuàng)建成功!')
}
}
}
</script>
你可以直接用我在案例中模擬獲取地址的那個路徑:
https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/bpmnMock.bpmn
案例Git地址: LinDaiDai-bpmn.js測試案例axios.vue
將編輯之后的最新bpmn發(fā)送給后臺
上面我們介紹了如何從后臺那里拿到數(shù)據(jù)并渲染到頁面上, 但這樣是不夠的.
可能你需要將編輯之后的最新bpmn存儲到后臺.
該功能就涉及到了bpmn.js中的事件綁定, 也就是前端需要給圖形綁定一個事件來檢測到圖形的改變, 并獲取到最新的xml 信息.
新建一個save.vue文件并將axios.vue里的內(nèi)容復(fù)制進(jìn)來.
在success()方法中添加一個addBpmnListener()綁定事件的方法:
// save.vue
<script>
success () {
console.log('創(chuàng)建成功!')
this.addBpmnListener()
},
// 添加綁定事件
addBpmnListener () {
const that = this
// 給圖綁定事件,當(dāng)圖有發(fā)生改變就會觸發(fā)這個事件
this.bpmnModeler.on('commandStack.changed', function () {
that.saveDiagram(function(err, xml) {
console.log(xml) // 這里獲取到的就是最新的xml信息
})
})
},
// 下載為bpmn格式,done是個函數(shù),調(diào)用的時候傳入的
saveDiagram(done) {
// 把傳入的done再傳給bpmn原型的saveXML函數(shù)調(diào)用
this.bpmnModeler.saveXML({ format: true }, function(err, xml) {
done(err, xml)
})
}
</script>
如圖所示:
案例Git地址: LinDaiDai-bpmn.js測試案例save.vue
編輯完保存為bpmn文件或svg文件
在上面我們監(jiān)聽commandStack.changed事件就能實時獲取到最新的xml信息.
拿到這些信息之后你可以選擇在每次圖形改變的時候就請求給后臺傳遞給他們最新的xml;
也可以選擇將其保存到一個變量中, 然后在頁面中給一個保存按鈕, 當(dāng)點(diǎn)擊按鈕的時候再傳遞給后臺.
或許你可能完全不需要再請求給后臺, 而是希望本地就能夠下載為bpmn文件或者svg文件.
在上面save.vue案例的基礎(chǔ)上增加兩個保存按鈕:
然后修改HTML代碼:
// save.vue
<template>
...
<ul class="buttons">
<li>
<a ref="saveDiagram" href="javascript:" title="保存為bpmn">保存為bpmn</a>
</li>
<li>
<a ref="saveSvg" href="javascript:" title="保存為svg">保存為svg</a>
</li>
</ul>
</template>
在js代碼中加上:
// save.vue
<script>
...
addBpmnListener () {
const that = this
// 獲取a標(biāo)簽dom節(jié)點(diǎn)
const downloadLink = this.$refs.saveDiagram
const downloadSvgLink = this.$refs.saveSvg
// 給圖綁定事件,當(dāng)圖有發(fā)生改變就會觸發(fā)這個事件
this.bpmnModeler.on('commandStack.changed', function () {
that.saveSVG(function(err, svg) {
that.setEncoded(downloadSvgLink, 'diagram.svg', err ? null : svg)
})
that.saveDiagram(function(err, xml) {
that.setEncoded(downloadLink, 'diagram.bpmn', err ? null : xml)
})
})
},
// 下載為SVG格式,done是個函數(shù),調(diào)用的時候傳入的
saveSVG(done) {
// 把傳入的done再傳給bpmn原型的saveSVG函數(shù)調(diào)用
this.bpmnModeler.saveSVG(done)
},
// 下載為bpmn格式,done是個函數(shù),調(diào)用的時候傳入的
saveDiagram(done) {
// 把傳入的done再傳給bpmn原型的saveXML函數(shù)調(diào)用
this.bpmnModeler.saveXML({ format: true }, function(err, xml) {
done(err, xml)
})
},
// 當(dāng)圖發(fā)生改變的時候會調(diào)用這個函數(shù),這個data就是圖的xml
setEncoded(link, name, data) {
// 把xml轉(zhuǎn)換為URI,下載要用到的
const encodedData = encodeURIComponent(data)
// 下載圖的具體操作,改變a的屬性,className令a標(biāo)簽可點(diǎn)擊,href令能下載,download是下載的文件的名字
console.log(link, name, data)
let xmlFile = new File([data], 'test.bpmn')
console.log(xmlFile)
if (data) {
link.className = 'active'
link.href = 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData
link.download = name
}
}
</script>
案例Git地址: LinDaiDai-bpmn.js測試案例save.vue 喜歡的小伙伴請給個Star??呀, 謝謝??
后語
系列全部目錄請查看此處: 《全網(wǎng)最詳bpmn.js教材》
系列相關(guān)推薦:
《全網(wǎng)最詳bpmn.js教材-基礎(chǔ)篇》
《全網(wǎng)最詳bpmn.js教材-renderer篇》