前言
Q: bpmn.js是什麼? ?️
”
bpmn.js是一個BPMN2.0渲染工具包和web建模器, 使得畫流程圖的功能在前端來完成.
Q: 我為什麼要寫該系列的教材? ?️
”
因為公司業務的需要因而要在專案中使用到bpmn.js
,但是由於bpmn.js
的開發者是國外友人, 因此國內對這方面的教材很少, 也沒有詳細的文件. 所以很多使用方式很多坑都得自己去找.在將其琢磨完之後, 決定寫一系列關於它的教材來幫助更多bpmn.js
的使用者或者是期於找到一種好的繪製流程圖的開發者. 同時也是自己對其的一種鞏固.
由於是系列的文章, 所以更新的可能會比較頻繁, 您要是無意間刷到了且不是您所需要的還請諒解?.
不求贊?不求心❤️. 只希望能對你有一點小小的幫助.
編輯、刪除節點篇
雖然前面已經說了很多關於如何建立, 渲染元素的知識, 但是在實際使用上肯定不僅僅只侷限於建立Task
、 Event
這些節點上.
你可能還需要建立: 線(bpmn:SequenceFlow
)、閘道器(ExclusiveGateway
)、活動(Activities
) 等等其他型別的節點.
甚至你想要在contextPad
中定義一個刪除、編輯節點的功能.
那麼這一章節我們主要就是來講解這些.
通過閱讀你可以學習到:
contextPad
上的刪除功能
讓我們接著上個章節的案例進行講解哈, 專案還是之前的專案LinDaiDai/bpmn-vue-custom
想要實現的功能是: 在contextPad
中加上一個刪除功能(這裡加上一個小垃圾桶):
並且點選它的時候可以刪除當前的節點...
讓我們開啟CustomContextPad.js
檔案或者CustomContextPadProvider.js
檔案, 然後在getContextPadEntries
方法中加上以下程式碼:
// CustomContextPad.js
getContextPadEntries(element) {
const { modeling } = this // modeling需要利用CustomContextPad.$inject註冊進來
function removeElement(e) { // 點選的時候實現刪除功能
modeling.removeElements([element])
}
function deleteElement() { // 建立垃圾桶
return {
group: 'edit',
className: 'icon-custom icon-custom-delete',
title: translate('刪除'),
action: {
click: removeElement
}
}
}
return {
'append.lindaidai-task': {...},
'delete': deleteElement() // 返回值加上刪除的功能
}
}
複製程式碼
可以看到要點就是:
將 modeling
引進來, 因為要使用到它的removeElements
方法;定義繪製垃圾桶的功能 編寫 className
來實現修改預設樣式的功能
OK?, 接下來別忘了在我們的app.css
中加上垃圾桶的樣式:
/* app.css*/
.icon-custom-delete {
background-image: url('https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/delete.png');
}
.djs-context-pad .icon-custom-delete.entry:hover {
background: url('https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/delete.png') center no-repeat!important;
background-size: cover!important;
}
複製程式碼
(自定義modeler
中的CustomContextPadProvider.js
也是這麼寫的)
這樣刪除功能就實現了.
contextPad
上的編輯功能
其實這裡說的編輯功能, 是指在contextPad
上定一個編輯的圖示, 然後點選的時候, 可以出現一個彈窗, 或者右邊出現一個自定義的properties-panel
, 然後這裡面可以顯示出節點的一些資訊.
這麼做的原因是:
你期望的可能不是點選節點的時候右邊出現 properties-panel
, 而是將properties-panel
作為一個抽屜隱藏在右側, 點選contextPad
中的某個圖示才從右側出來.點選 contextPad
中的某個圖示獲取到當前節點的節點資訊然後做其他自定義的操作.
通過點選小圖示獲取節點資訊
如上圖, 先實現這個功能: 點選編輯圖示, 將節點資訊列印出來.
其實也很簡單, 經過了lindaidi-task
和delete
之後, 我相信你也掌握了一些規律了.
反正要建立什麼圖示就往getContextPadEntries
的返回值加就可以了:
// CustomContextPad.js
getContextPadEntries(element) {
function clickElement(e) {
console.log(element)
}
function editElement() { // 建立編輯圖示
return {
group: 'edit',
className: 'icon-custom icon-custom-edit',
title: translate('編輯'),
action: {
click: clickElement
}
}
}
return {
'append.lindaidai-task': {...},
'edit': editElement(), // 返回值加上編輯功能
'delete': deleteElement() // 返回值加上刪除的功能
}
}
複製程式碼
然後記得在app.css
中加上.icon-custom-edit
的樣式, 這裡就不貼程式碼了.
將節點的資訊傳遞出去
其實我們會發現, 通過點選小圖示獲取到節點資訊很容易就實現了, 但是如何將在CustomContextPad.js
中的資訊傳遞出去呢, 也就是我們在頁面上該怎麼拿到這個資訊呢?
比如我想實現: 點選上面?所說的編輯小圖示, 然後出現這麼一個彈窗, 顯示出節點的相關資訊:
(由於沒有引入任何的UI
元件, 所以隨手寫了一些樣式)
哈哈?, 方法其實也有很多種:
前端本地儲存 localStorage
vue
的vuex
react
的redux
以上技術都可以實現...
由於專案是用vue
開發的, 所以這裡我就演示一下利用vuex
來進行互動?.
首先在我們的專案裡安裝上vuex
:
$ npm i vuex --save-D
複製程式碼
然後在src
目錄下建立好一個store
資料夾用來存放它, 並記得在main.js
用進行引用:
// main.js
import store from './store'
...
new Vue({
...
store,
render: h => h(App),
}).$mount('#app')
複製程式碼
讓我們在store
中建立一個叫做bpmn
模組, 專門用來定義bpmn
相關的儲存. 然後在其中定義:
nodeInfo<Object>
: 用於儲存當前點選的節點的資訊nodeVisible<Boolean>
: 用於判斷彈窗顯示隱藏的變數
// store/modules/bpmn.js
const bpmn = {
state: {
nodeVisible: false,
nodeInfo: {}
},
mutations: {
TOGGLENODEVISIBLE: (state, visible) => {
state.nodeVisible = visible
},
SETNODEINFO: (state, info) => {
state.nodeInfo = info
}
},
actions: {}
}
export default bpmn
複製程式碼
定義好這些之後, 我們就可以在CustomContextPadProvider.js
裡的clickElement
做文章了:
// CustomContextPadProvider.js
import store from '../../../store' // 引入store
function clickElement(e) {
console.log(element)
store.commit('SETNODEINFO', element) // 儲存節點資訊
store.commit('TOGGLENODEVISIBLE', true)
}
複製程式碼
由於CustomContextPadProvider.js
和CustomContextPad.js
的做法都是一樣的, 這裡我就以CustomContextPadProvider.js
為案例進行講解.
通過以上的步驟, 已經可以將這兩個值儲存到store
中了, 接下來只是看看頁面上該如何呼叫它們.
讓我們開啟custom-modeler.vue
檔案, 給裡面加個小彈窗:
<template>
<div class="modal" v-if="bpmnNodeVisible" @click="close">
<div class="modal-content">
<div class="modal-ctx">
<div class="modal-item">
節點id: {{ bpmnNodeInfo.id }}
</div>
<div class="modal-item">
節點type: {{ bpmnNodeInfo.type }}
</div>
</div>
</div>
</div>
</template>
複製程式碼
彈窗樣式隨便寫了點, 在專案程式碼裡可以看到, 這裡就不貼了.
然後編輯相關的js
程式碼:
<script>
import { mapState, mapMutations } from 'vuex'
export default {
... // 這個省略號是省略程式碼
methods: { // 方法
...mapMutations(['TOGGLENODEVISIBLE']), // 這個省略號是解構
close () {
this.TOGGLENODEVISIBLE(false)
}
},
computed: { // 計算屬性
...mapState({ // 解構
bpmnNodeInfo: state => state.bpmn.nodeInfo,
bpmnNodeVisible: state => state.bpmn.nodeVisible
})
}
}
</script>
複製程式碼
完成了上面的步驟之後, 我們就實現了點選contextPad
中的編輯圖示, 出現顯示節點相關資訊的小彈窗, 點選陰影出關閉小彈窗的功能了, 當然了你也可以在關閉的時候, 清空掉store
中的節點資訊nodeInfo
, 這裡就不做這些操作了.
最後讓我們來梳理一下, 前面的關鍵步驟:
引用 vuex
來實現跨元件傳遞資料;在點選編輯小圖示的時候將節點資訊儲存到 store
中;頁面要使用的時候, 利用 vue
中計算屬效能夠監聽state
的改變的原理來更新你的UI
(也就是出現彈窗)
(我開始是想用最簡單的localStorage
來實現的, 後來發現computed
不能夠監聽到它的改變, 導致localStorage
中的nodeVisible
雖然已經變化了, 但是bpmnNodeVisible
還是沒有. 因此後來轉用了vuex
)
後語
其實這一章節主要是給大家傳遞一種思路, 如何將contextPad
與你的頁面結合起來, 講解中只是說了一種最簡單的出現小彈窗的情況, 可能在實際開發中你會有更多複雜的需求, 複雜的互動.
不過也很高興能給你提供一個這樣的解決方案, 也可以說給你一點靈感吧?...
因為自己在研究bpmn.js
的時候, 也是沒有任何人指導, 全靠自己檢視官方案例還有絞盡腦汁的想, 所以我才明白這玩意的麻煩... 哈哈哈?, 扯多了, 這一章節就到這裡吧.
上面?案例用的都是同一個專案?
專案案例Git地址: LinDaiDai/bpmn-vue-custom 喜歡的小夥伴請給個Star
?呀, 謝謝?
系列全部目錄請檢視此處: 《全網最詳bpmn.js教材》
系列相關推薦: