全网最详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篇》

相关文章
相关标签/搜索