全網最詳bpmn.js教材-事件篇

前言

Q: bpmn.js是什麼? 🤔️javascript

bpmn.js是一個BPMN2.0渲染工具包和web建模器, 使得畫流程圖的功能在前端來完成.前端

Q: 我爲何要寫該系列的教材? 🤔️vue

由於公司業務的須要於是要在項目中使用到bpmn.js,可是因爲bpmn.js的開發者是國外友人, 所以國內對這方面的教材不多, 也沒有詳細的文檔. 因此不少使用方式不少坑都得本身去找.在將其琢磨完以後, 決定寫一系列關於它的教材來幫助更多bpmn.js的使用者或者是期於找到一種好的繪製流程圖的開發者. 同時也是本身對其的一種鞏固.java

因爲是系列的文章, 因此更新的可能會比較頻繁, 您要是無心間刷到了且不是您所須要的還請諒解😊.git

不求贊👍不求心❤️. 只但願能對你有一點小小的幫助.github

事件篇

上一章節咱們介紹了利用bpmn.js與後臺進行交互, 要是對bpmn.js不瞭解的小夥請移步:web

《全網最詳bpmn.js教材-http請求篇》bash

這一章節要講解是關於bpmn.js的一些事件, 經過學習此章節你能夠學習到:dom

監聽modeler並綁定事件

不少時候你指望的是在用戶在進行不一樣操做的時候可以監聽到他操做的是什麼, 從而作想要作的事情.svg

是進行了shape的新增仍是進行了線的新增.

好比以下的一些監聽事件:

  • shape.added 新增一個shape以後觸發;
  • shape.move.end 移動完一個shape以後觸發;
  • shape.removed 刪除一個shape以後觸發;

繼續在項目案例bpmn-vue-basic的基礎上建立一個event.vue文件:

並在success()函數中添加上監聽事件的函數:

// event.vue
<script>
...
success () {
  this.addModelerListener()
},
// 監聽 modeler
addModelerListener() {
  const bpmnjs = this.bpmnModeler
  const that = this
  // 這裏我是用了一個forEach給modeler上添加要綁定的事件
  const events = ['shape.added', 'shape.move.end', 'shape.removed', 'connect.end', 			'connect.move']
  events.forEach(function(event) {
    that.bpmnModeler.on(event, e => {
      console.log(event, e)
      var elementRegistry = bpmnjs.get('elementRegistry')
      var shape = e.element ? elementRegistry.get(e.element.id) : e.shape
      console.log(shape)
    })
  })
},
複製代碼

如圖所示, 在這裏你就能夠獲取到相關節點的全部信息了:

img1

案例Git地址: LinDaiDai-bpmn.js案例event.vue

其實具體有哪些事件我在官網上都沒有找到說明, 以上只是我在查找到bpmn.io/diagram.js/…文件以後, 取的一些我項目裏有用到的事件.

監聽element並綁定事件

上面介紹的是監聽modeler並綁定事件, 可能你也須要監聽用戶點擊圖形上的element或者監聽某個element改變:

  • element.click 點擊元素;
  • element.changed 當元素髮生改變的時候(包括新增、移動、刪除元素)

繼續在success()上添加監聽事件:

// event.vue
<script>
...
success () {
	...
	this.addEventBusListener()
},
addEventBusListener () {
	let that = this
  const eventBus = this.bpmnModeler.get('eventBus') // 須要使用eventBus
  const eventTypes = ['element.click', 'element.changed'] // 須要監聽的事件集合
  eventTypes.forEach(function(eventType) {
    eventBus.on(eventType, function(e) {
      console.log(e)
    })
  })
}
</script>
複製代碼

配置好addEventBusListener()函數後, 在進行元素的點擊、新增、移動、刪除的時候都能監聽到了.

可是有一點很很差, 你在點擊「畫布」的時候, 也就是根元素也可能會觸發此事件, 咱們通常都不但願此時會觸發, 所以咱們能夠在on回調中添加一些判斷, 來避免掉不須要的狀況:

eventBus.on(eventType, function(e) {
  if (!e || e.element.type == 'bpmn:Process') return // 這裏個人根元素是bpmn:Process
  console.log(e)
})
複製代碼

此時咱們能夠把監聽到返回的節點信息打印出來看看:

img2

如上圖, 它會打印出該節點的Shape信息和DOM信息等, 但咱們可能只關注於Shape信息(也就是該節點的id、type等等信息), 此時咱們可使用elementRegistry來獲取Shape信息:

eventBus.on(eventType, function(e) {
  if (!e || e.element.type == 'bpmn:Process') return // 這裏個人根元素是bpmn:Process
  console.log(e)
  var elementRegistry = this.bpmnModeler.get('elementRegistry')
  var shape = elementRegistry.get(e.element.id) // 傳遞id進去
  console.log(shape) // {Shape}
  console.log(e.element) // {Shape}
  console.log(JSON.stringify(shape)===JSON.stringify(e.element)) // true
})

複製代碼

或者你也能夠直接就用e.element獲取到Shape的信息, 我比較了一下它們兩是同樣的. 可是官方是推薦使用elementRegistry的方式.

經過監聽事件判斷操做方式

上面咱們已經介紹了modelerelement的監聽綁定方式, 在事件應用中, 你更多的須要知道用戶要進行什麼操做, 好寫對應的業務邏輯.

這裏我就以我工做中要用到的場景爲案例進行講解.

  • 新增了shape
  • 新增了線(connection)
  • 刪除了shape和connection
  • 移動了shape和線
// event.vue
    ...
    success () {
      this.addModelerListener()
      this.addEventBusListener()
    },
    // 添加綁定事件
    addBpmnListener () {
      const that = this
      // 獲取a標籤dom節點
      const downloadLink = this.$refs.saveDiagram
      const downloadSvgLink = this.$refs.saveSvg
        // 給圖綁定事件,當圖有發生改變就會觸發這個事件
      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)
        })
      })
    },
    addModelerListener() {
      // 監聽 modeler
      const bpmnjs = this.bpmnModeler
      const that = this
      // 'shape.removed', 'connect.end', 'connect.move'
      const events = ['shape.added', 'shape.move.end', 'shape.removed']
      events.forEach(function(event) {
        that.bpmnModeler.on(event, e => {
          var elementRegistry = bpmnjs.get('elementRegistry')
          var shape = e.element ? elementRegistry.get(e.element.id) : e.shape
          // console.log(shape)
          if (event === 'shape.added') {
            console.log('新增了shape')
          } else if (event === 'shape.move.end') {
            console.log('移動了shape')
          } else if (event === 'shape.removed') {
            console.log('刪除了shape')
          }
        })
      })
    },
    addEventBusListener() {
      // 監聽 element
      let that = this
      const eventBus = this.bpmnModeler.get('eventBus')
      const eventTypes = ['element.click', 'element.changed']
      eventTypes.forEach(function(eventType) {
        eventBus.on(eventType, function(e) {
          if (!e || e.element.type == 'bpmn:Process') return
          if (eventType === 'element.changed') {
            that.elementChanged(eventType, e)
          } else if (eventType === 'element.click') {
            console.log('點擊了element')
          }
        })
      })
    },
    elementChanged(eventType, e) {
      var shape = this.getShape(e.element.id)
      if (!shape) {
        // 如果shape爲null則表示刪除, 不管是shape仍是connect刪除都調用此處
        console.log('無效的shape')
        // 因爲上面已經用 shape.removed 檢測了shape的刪除, 所以這裏只判斷是不是線
        if (this.isSequenceFlow(shape.type)) {
          console.log('刪除了線')
        }
      }
      if (!this.isInvalid(shape.type)) {
        if (this.isSequenceFlow(shape.type)) {
          console.log('改變了線')
        }
      }
    },
    getShape(id) {
      var elementRegistry = this.bpmnModeler.get('elementRegistry')
      return elementRegistry.get(id)
    },
    isInvalid (param) { // 判斷是不是無效的值
      return param === null || param === undefined || param === ''
    },
    isSequenceFlow (type) { // 判斷是不是線
      return type === 'bpmn:SequenceFlow'
    }
複製代碼

案例Git地址: LinDaiDai-bpmn.js案例event.vue

後語

系列相關推薦

《全網最詳bpmn.js教材-基礎篇》

《全網最詳bpmn.js教材-http請求篇》

《全網最詳bpmn.js教材-自定義palette篇》

相關文章
相關標籤/搜索