前言
Q: bpmn.js是什么? ???
bpmn.js是一個BPMN2.0渲染工具包和web建模器, 使得畫流程圖的功能在前端來完成.
Q: 我為什么要寫該系列的教材? ???
因為公司業(yè)務的需要因而要在項目中使用到bpmn.js
,但是由于bpmn.js
的開發(fā)者是國外友人, 因此國內對這方面的教材很少, 也沒有詳細的文檔. 所以很多使用方式很多坑都得自己去找.在將其琢磨完之后, 決定寫一系列關于它的教材來幫助更多bpmn.js
的使用者或者是期于找到一種好的繪制流程圖的開發(fā)者. 同時也是自己對其的一種鞏固.
由于是系列的文章, 所以更新的可能會比較頻繁, 您要是無意間刷到了且不是您所需要的還請諒解??.
不求贊??不求心??. 只希望能對你有一點小小的幫助.
編輯、刪除節(jié)點篇
雖然前面已經說了很多關于如何創(chuàng)建, 渲染元素的知識, 但是在實際使用上肯定不僅僅只局限于創(chuàng)建Task
妆毕、 Event
這些節(jié)點上.
你可能還需要創(chuàng)建: 線(bpmn:SequenceFlow
)慎玖、網關(ExclusiveGateway
)、活動(Activities
) 等等其他類型的節(jié)點.
甚至你想要在contextPad
中定義一個刪除笛粘、編輯節(jié)點的功能.
那么這一章節(jié)我們主要就是來講解這些.
通過閱讀你可以學習到:
contextPad
上的刪除功能
讓我們接著上個章節(jié)的案例進行講解哈, 項目還是之前的項目LinDaiDai/bpmn-vue-custom
想要實現的功能是: 在contextPad
中加上一個刪除功能(這里加上一個小垃圾桶):
并且點擊它的時候可以刪除當前的節(jié)點...
讓我們打開CustomContextPad.js
文件或者CustomContextPadProvider.js
文件, 然后在getContextPadEntries
方法中加上以下代碼:
// CustomContextPad.js
getContextPadEntries(element) {
const { modeling } = this // modeling需要利用CustomContextPad.$inject注冊進來
function removeElement(e) { // 點擊的時候實現刪除功能
modeling.removeElements([element])
}
function deleteElement() { // 創(chuàng)建垃圾桶
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
, 然后這里面可以顯示出節(jié)點的一些信息.
這么做的原因是:
- 你期望的可能不是點擊節(jié)點的時候右邊出現
properties-panel
, 而是將properties-panel
作為一個抽屜隱藏在右側, 點擊contextPad
中的某個圖標才從右側出來. - 點擊
contextPad
中的某個圖標獲取到當前節(jié)點的節(jié)點信息然后做其他自定義的操作.
通過點擊小圖標獲取節(jié)點信息
如上圖, 先實現這個功能: 點擊編輯圖標, 將節(jié)點信息打印出來.
其實也很簡單, 經過了lindaidi-task
和delete
之后, 我相信你也掌握了一些規(guī)律了.
反正要創(chuàng)建什么圖標就往getContextPadEntries
的返回值加就可以了:
// CustomContextPad.js
getContextPadEntries(element) {
function clickElement(e) {
console.log(element)
}
function editElement() { // 創(chuàng)建編輯圖標
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
的樣式, 這里就不貼代碼了.
將節(jié)點的信息傳遞出去
其實我們會發(fā)現, 通過點擊小圖標獲取到節(jié)點信息很容易就實現了, 但是如何將在CustomContextPad.js
中的信息傳遞出去呢, 也就是我們在頁面上該怎么拿到這個信息呢?
比如我想實現: 點擊上面??所說的編輯小圖標, 然后出現這么一個彈窗, 顯示出節(jié)點的相關信息:
(由于沒有引入任何的UI
組件, 所以隨手寫了一些樣式)
哈哈??, 方法其實也有很多種:
- 前端本地存儲
localStorage
-
vue
的vuex
-
react
的redux
以上技術都可以實現...
由于項目是用vue
開發(fā)的, 所以這里我就演示以下利用vuex
來進行交互??.
首先在我們的項目里安裝上vuex
:
$ npm i vuex --save-D
然后在src
目錄下創(chuàng)建好一個store
文件夾用來存放它, 并記得在main.js
用進行引用:
// main.js
import store from './store'
...
new Vue({
...
store,
render: h => h(App),
}).$mount('#app')
讓我們在store
中創(chuàng)建一個叫做bpmn
模塊, 專門用來定義bpmn
相關的存儲. 然后在其中定義:
-
nodeInfo<Object>
: 用于存儲當前點擊的節(jié)點的信息 -
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) // 存儲節(jié)點信息
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">
節(jié)點id: {{ bpmnNodeInfo.id }}
</div>
<div class="modal-item">
節(jié)點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
中的編輯圖標, 出現顯示節(jié)點相關信息的小彈窗, 點擊陰影出關閉小彈窗的功能了, 當然了你也可以在關閉的時候, 清空掉store
中的節(jié)點信息nodeInfo
, 這里就不做這些操作了.
最后讓我們來梳理一下, 前面的關鍵步驟:
- 引用
vuex
來實現跨組件傳遞數據; - 在點擊編輯小圖標的時候將節(jié)點信息存儲到
store
中; - 頁面要使用的時候, 利用
vue
中計算屬性能夠監(jiān)聽state
的改變的原理來更新你的UI
(也就是出現彈窗)
(我開始是想用最簡單的localStorage
來實現的, 后來發(fā)現computed
不能夠監(jiān)聽到它的改變, 導致localStorage
中的nodeVisible
雖然已經變化了, 但是bpmnNodeVisible
還是沒有. 因此后來轉用了vuex
)
后語
其實這一章節(jié)主要是給大家傳遞一種思路, 如何將contextPad
與你的頁面結合起來, 講解中只是說了一種最簡單的出現小彈窗的情況, 可能在實際開發(fā)中你會有更多復雜的需求, 復雜的交互.
不過也很高興能給你提供一個這樣的解決方案, 也可以說給你一點靈感吧??...
因為自己在研究bpmn.js
的時候, 也是沒有任何人指導, 全靠自己查看官方案例還有絞盡腦汁的想, 所以我才明白這玩意的麻煩... 哈哈哈??, 扯多了, 這一章節(jié)就到這里吧.
上面??案例用的都是同一個項目??
項目案例Git地址: LinDaiDai/bpmn-vue-custom 喜歡的小伙伴請給個Star
??呀, 謝謝??
系列全部目錄請查看此處: 《全網最詳bpmn.js教材》
系列相關推薦: