elementUi + Vue-super-flow 实现树节点可拖拽绘制流程图
实现将左边树节点拖曳到中间区域,并用线连接起来,形成流程图,且树节点只能拖到中间区域,不可进行上下层级之间拖动,即树节点在左侧的位置不变
·
如下图所示:实现将左边树节点拖曳到中间区域,并用线连接起来,形成流程图,且树节点只能拖到中间区域,不可进行上下层级之间拖动,即树节点在左侧的位置不变。
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)
},
更多推荐
已为社区贡献1条内容
所有评论(0)