如下图所示:实现将左边树节点拖曳到中间区域,并用线连接起来,形成流程图,且树节点只能拖到中间区域,不可进行上下层级之间拖动,即树节点在左侧的位置不变。
在这里插入图片描述

1、安装Vue-super-flow
Vue-super-flow 是基于vue 开发的一款生成、预览流程图的组件,用户可以根据不同的需求对图、节点、连线进行操作。
终端输入以下语句安装Vue-super-flow依赖

npm install vue-super-flow

2、引用Vue-super-flow
在main.js文件中添加以下语句,引用Vue-super-flow

import SuperFlow from 'vue-super-flow'
import 'vue-super-flow/lib/index.css'

Vue.use(SuperFlow)

3、html部分代码如下:

<super-flow
  ref="superFlow"
  :node-list="nodeList"
  :link-list="linkList"
  :graph-menu="graphMenu"
  :node-menu="nodeMenu"
  :link-menu="linkMenu"
  :link-base-style="linkBaseStyle"
  :link-style="linkStyle"
  :link-desc="linkDesc">
  <template v-slot:node="{meta}">
    <div
      @mouseup="nodeMouseUp"
      style="line-height: 30px;text-align: center;color: white;background: #3a8ee6"
      class="flow-node ellipsis">
      {{ meta.name }}
    </div>
  </template>
</super-flow>

JS核心代码如下:

const drawerType = {
  node: 0,
  link: 1
}

export default {
  data () {
    return { 
      linkList: [],
      nodeList: [
        {
          id: 'nodeStart',
          width: 120,
          height: 30,
          coordinate: [
            10,
            10
          ],
          meta: {
            lable: '',
            name: '开始',
            algoId: '0',
            nextNodeId: [],
            nextAlgoId: []
          }
        },
        {
          id: 'nodeEnd',
          width: 120,
          height: 30,
          coordinate: [
            10,
            50
          ],
          meta: {
            lable: '',
            name: '结束',
            algoId: '1',
            nextNodeId: [],
            nextAlgoId: []
          }
        }
      ],
      drawerConf: {
        title: '',
        visible: false,
        type: null,
        info: null,
        open: (type, info) => {
          const conf = this.drawerConf
          conf.visible = true
          conf.type = type
          conf.info = info
          if (conf.type === drawerType.node) {
            conf.title = '算法详情'
            if (this.$refs.nodeSetting) this.$refs.nodeSetting.resetFields()
            this.$set(this.nodeSetting, 'name', info.meta.name)
            this.$set(this.nodeSetting, 'desc', info.meta.desc)
            this.nodeSetting.Items = []
        },
        cancel: () => {
          this.drawerConf.visible = false
          if (this.drawerConf.type === drawerType.node) {
            this.$refs.nodeSetting.clearValidate()
          } else {
            this.$refs.linkSetting.clearValidate()
          }
        }
      },
      linkSetting: {
        desc: ''
      },
      nodeSetting: {
        name: '',
        desc: '',
        ExeName: '',
        Items: []
      },

      dragConf: {
        isDown: false,
        isMove: false,
        offsetTop: 0,
        offsetLeft: 0,
        clientX: 0,
        clientY: 0,
        ele: null,
        info: null
      },
      data: [],
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      graphMenu: [
        [
          {
            label: '全选',
            selected: graph => {
              graph.selectAll()
            }
          }
        ],
        [
          {
            label: '保存产线流程图',
            selected: () => {
              this.registerFlow('ruleForm')
            }
          }
        ]
      ],
      // node 右键菜单配置
      nodeMenu: [
        [
          {
            label: '删除算法',
            selected: node => {
             node.remove()
            }
          },
          {
            label: '查看详情',
            selected: node => {
              this.drawerConf.open(drawerType.node, node)
            }
          }
        ]
      ],
      linkMenu: [
        [
          {
            label: '删除',
            selected: link => {
              link.remove()
            }
          },
          {
            label: '编辑',
            selected: link => {
              this.drawerConf.open(drawerType.link, link)
            }
          }
        ]
      ],

      linkBaseStyle: {
        color: '#000', // line 颜色
        hover: '#666666', // line hover 的颜色
        textColor: '#666666', // line 描述文字颜色
        textHover: '#FF0000', // line 描述文字 hover 颜色
        font: '14px Arial', // line 描述文字 字体设置 参考 canvas font
        dotted: false, // 是否是虚线
        lineDash: [4, 4], // 虚线时生效
        background: 'rgba(255,255,255,0.6)' // 描述文字背景色
      },
      fontList: [
        '14px Arial',
        'italic small-caps bold 12px arial'
      ],
      nodeSub: null
    }
  },
  mounted () {
    document.addEventListener('mousemove', this.docMousemove)
    document.addEventListener('mouseup', this.docMouseup)
    this.$once('hook:beforeDestroy', () => {
      document.removeEventListener('mousemove', this.docMousemove)
      document.removeEventListener('mouseup', this.docMouseup)
    })
  },

  methods: {
    // 拖拽控制
    allowDrop (moveNode, inNode, type) {
     //限制树节点拖拽后是否可以放置在当前位置,值为true时可以,为false时不可以
      return false
    },
    nodeDragStart (node, event) {
      const {
        clientX,
        clientY,
        currentTarget
      } = event

      const {
        top,
        left
      } = event.currentTarget.getBoundingClientRect()

      const conf = this.dragConf
      const ele = currentTarget.cloneNode(true)

      Object.assign(this.dragConf, {
        offsetLeft: clientX - left,
        offsetTop: clientY - top,
        clientX: clientX,
        clientY: clientY,
        info: node.data.value(),
        ele,
        isDown: true
      })

      ele.style.position = 'fixed'
      ele.style.margin = '0'
      ele.style.top = clientY - conf.offsetTop + 'px'
      ele.style.left = clientX - conf.offsetLeft + 'px'

      this.$el.appendChild(this.dragConf.ele)
    },
    linkStyle (link) {
      if (link.meta && link.meta.desc === '1') {
        return {
          color: 'red',
          hover: '#FF00FF',
          dotted: true
        }
      } else {
        return {}
      }
    },
    linkDesc (link) {
      return link.meta ? link.meta.desc : ''
    },
    nodeMouseUp (evt) {
      evt.preventDefault()
    },
    docMousemove ({ clientX, clientY }) {
      const conf = this.dragConf

      if (conf.isMove) {
        conf.ele.style.top = clientY - conf.offsetTop + 'px'
        conf.ele.style.left = clientX - conf.offsetLeft + 'px'
      } else if (conf.isDown) {
        // 鼠标移动量大于 5 时 移动状态生效
        conf.isMove =
                        Math.abs(clientX - conf.clientX) > 5 ||
                        Math.abs(clientY - conf.clientY) > 5
      }
    },
    docMouseup ({ clientX, clientY }) {
      console.log('docMouseupgraph=', this.$refs.superFlow.graph)
      const conf = this.dragConf
      conf.isDown = false

      if (conf.isMove) {
        const {
          top,
          right,
          bottom,
          left
        } = this.$refs.flowContainer.getBoundingClientRect()

        // 判断鼠标是否进入 flow container
        if (
          clientX > left &&
                        clientX < right &&
                        clientY > top &&
                        clientY < bottom
        ) {
          // 获取拖动元素左上角相对 super flow 区域原点坐标
          const coordinate = this.$refs.superFlow.getMouseCoordinate(
            clientX - conf.offsetLeft,
            clientY - conf.offsetTop
          )

          // 添加节点
          this.$refs.superFlow.addNode({
            coordinate,
            ...conf.info
          })
        }

        conf.isMove = false
      }

      if (conf.ele) {
        conf.ele.remove()
        conf.ele = null
      }
    }
  }
}

4、el-tree组件代码:

<el-tree
	 :style="cssVar"
	  class="flow-tree"
	  :data="TreeData"
	  :default-expanded-keys="[2, 3]"
	  :default-checked-keys="[5]"
	  :props="defaultProps"
	  default-expand-all
	  draggable="true"
	  :allow-drop="allowDrop"
	  @node-drag-start="nodeDragStart">
</el-tree>

allow-drop属性是用来限制树节点拖拽后是否可以放置在当前位置,属性值为true时可以,为false时不可以。

// 拖拽控制
allowDrop (moveNode, inNode, type) {
  //限制树节点拖拽后是否可以放置在当前位置,值为true时可以,为false时不可以
  return false
}

拖曳开始时处理代码如下:

nodeDragStart (node, event) {
      const {
        clientX,
        clientY,
        currentTarget
      } = event

      const {
        top,
        left
      } = event.currentTarget.getBoundingClientRect()

      const conf = this.dragConf
      const ele = currentTarget.cloneNode(true)

      Object.assign(this.dragConf, {
        offsetLeft: clientX - left,
        offsetTop: clientY - top,
        clientX: clientX,
        clientY: clientY,
        info: node.data.value(),
        ele,
        isDown: true
      })

      ele.style.position = 'fixed'
      ele.style.margin = '0'
      ele.style.top = clientY - conf.offsetTop + 'px'
      ele.style.left = clientX - conf.offsetLeft + 'px'

      this.$el.appendChild(this.dragConf.ele)
},

更多推荐