随着互联网的发展,越来越多的应用需要实现流程图的制作,如工作流程图、电路图等。而 vue.js 作为一款非常流行的前端框架,提供了极佳的交互性和可维护性,因此被广泛应用于构建复杂的流程图应用程序。
本文将介绍如何使用 vue 实现流程图制作,包括以下步骤:
安装必要的依赖编写基本的组件结构实现拖拽功能实现连接线实现节点编辑导出流程图安装必要的依赖首先,我们需要安装 vue-draggable-resizable 库,它是一个非常好用的 vue 插件,能够实现元素的拖拽和缩放功能。我们可以使用 npm 安装:
npm install vue-draggable-resizable --save
编写基本的组件结构我们需要使用 vue 组件来实现流程图的编辑。我们需要创建一个 flowchart 组件,用于包含所有流程图元素。每个节点都是 node 组件,用于表示流程图中的一个步骤。连接线是 connection 组件,用于连接不同的节点。
首先,我们需要在 flowchart.vue 文件中创建一个抽象的 flowchart 组件,用于包含所有节点和连接线:
<template> <div class="flowchart"> <div class="nodes"> <!-- 组件插槽,用于插入节点 --> <slot name="nodes"></slot> </div> <svg class="connections"> <!-- 组件插槽,用于插入连接线 --> <slot name="connections"></slot> </svg> </div></template><script>export default { name: 'flowchart'}</script>
我们将节点和连接线分别放在 flowchart 组件的两个插槽中。
接下来,我们需要创建 node 和 connection 组件,用于表示流程图的节点和连接线:
node.vue:
<template> <draggable-resizable :w="width" :h="height" :x="x" :y="y"> <div class="node"> <!-- 节点的内容 --> <div class="node-content"> <slot></slot> </div> </div> </draggable-resizable></template><script>import vuedraggableresizable from 'vue-draggable-resizable'export default { name: 'node', components: { vuedraggableresizable }, props: { width: { type: number, default: 100 }, height: { type: number, default: 50 }, x: { type: number, default: 0 }, y: { type: number, default: 0 } }}</script>
connection.vue:
<template> <svg class="connection"> <!-- svg 路径元素,用于绘制连接线 --> <path :d="path"></path> </svg></template><script>export default { name: 'connection', props: { start: object, end: object }, computed: { path () { // 计算连接线的路径 const startx = this.start.x + this.start.width / 2 const starty = this.start.y + this.start.height / 2 const endx = this.end.x + this.end.width / 2 const endy = this.end.y + this.end.height / 2 return `m ${startx} ${starty} l ${endx} ${endy}` } }}</script>
我们使用 vue-draggable-resizable 组件来实现节点的拖拽和缩放,其中需要传递节点的 width、height、x、y 等属性。连接线则使用 svg 的路径元素来绘制,需要根据节点的位置和尺寸计算出路径。
实现拖拽功能为了实现节点的拖拽功能,我们需要在 node 组件中添加 v-on:drag、v-on:dragstop 和 v-on:resize 事件监听器。它们分别对应节点的拖拽、结束拖拽和调整大小:
<draggable-resizable :w="width" :h="height" :x="x" :y="y" v-on:drag="ondrag" v-on:dragstop="ondragstop" v-on:resize="onresize"> <!-- 节点的内容 --></draggable-resizable><script>export default { name: 'node', methods: { ondrag (pos) { // 拖拽事件处理函数 this.$emit('move', { x: pos.x, y: pos.y }) }, ondragstop (pos) { // 结束拖拽事件处理函数 this.$emit('endmove', { x: pos.x, y: pos.y }) }, onresize (size) { // 调整大小事件处理函数 this.$emit('resize', { width: size.width, height: size.height }) } }}</script>
我们在这些事件处理函数中通过 $emit 方法向父组件发送事件,从而实现节点位置和大小的实时更新。在 flowchart 组件中,我们需要监听这些事件并更新节点的信息:
<template> <div class="flowchart"> <div class="nodes"> <!-- 将节点插入到插槽中 --> <slot name="nodes"></slot> </div> <svg class="connections"> <!-- 将连接线插入到插槽中 --> <slot name="connections"></slot> <!-- 鼠标跟随的连接线 --> <connection v-if="showconnection" :start="{x: start.x + start.width / 2, y: start.y + start.height / 2, width: start.width, height: start.height}" :end="{x: end.x + end.width / 2, y: end.y + end.height / 2, width: end.width, height: end.height}"/> </svg> </div></template><script>import node from './node.vue'import connection from './connection.vue'export default { name: 'flowchart', components: { node, connection }, data () { return { showconnection: false, start: null, // 起点节点 end: null // 终点节点 } }, methods: { onnodemove (node, pos) { // 节点拖拽时的事件处理函数 node.x = pos.x node.y = pos.y }, onnodeendmove (node, pos) { // 节点结束拖拽时的事件处理函数 node.x = pos.x node.y = pos.y this.showconnection = false this.start = null this.end = null }, onnoderesize (node, size) { // 节点调整大小时的事件处理函数 node.width = size.width node.height = size.height }, connectnodes (start, end) { // 连接两个节点 this.showconnection = true this.start = start this.end = end } }}</script>
我们定义了 onnodemove、onnodeendmove 和 onnoderesize 三个事件处理函数,用于响应节点的拖拽、结束拖拽和调整大小。connectnodes 函数用于连接两个节点。
实现连接线在 flowchart 组件中,我们定义了一个 showconnection 变量和两个变量 start 和 end,用于保存连接线的信息。我们需要通过鼠标事件来更新这些信息,从而实现连接线的绘制。
首先,我们需要在 node 组件中添加对 v-on:mousedown 和 v-on:mouseup 事件的监听。这些事件用于检测用户是否选择了一个节点:
<draggable-resizable :w="width" :h="height" :x="x" :y="y" v-on:drag="ondrag" v-on:dragstop="ondragstop" v-on:resize="onresize" v-on:mousedown="onmousedown" v-on:mouseup="onmouseup"> <!-- 节点的内容 --></draggable-resizable><script>export default { name: 'node', methods: { ... onmousedown () { // 鼠标按下时选中当前节点 this.$emit('select', this) }, onmouseup () { // 鼠标松开时取消选中 this.$emit('unselect') } }}</script>
我们在 onmousedown 事件处理函数中向父组件发送一个 select 事件,用于选中当前节点。在 flowchart 组件中,我们需要监听这个事件:
<template> <div class="flowchart"> <div class="nodes"> <!-- 将节点插入到插槽中 --> <slot name="nodes"></slot> </div> <svg class="connections"> <!-- 将连接线插入到插槽中 --> <slot name="connections"></slot> <!-- 鼠标跟随的连接线 --> <connection v-if="showconnection" :start="{x: start.x + start.width / 2, y: start.y + start.height / 2, width: start.width, height: start.height}" :end="{x: end.x + end.width / 2, y: end.y + end.height / 2, width: end.width, height: end.height}"/> </svg> </div></template><script>import node from './node.vue'import connection from './connection.vue'export default { name: 'flowchart', components: { node, connection }, data () { return { showconnection: false, start: null, // 起点节点 end: null // 终点节点 } }, methods: { ... onselectnode (node) { // 选中节点时的事件处理函数 if (this.start) { // 已选择起点,连接当前节点 this.end = node this.connectnodes(this.start, this.end) } else { // 选择起点 this.start = node } }, onunselectnode () { // 取消选中节点时的事件处理函数 this.start = null this.end = null this.showconnection = false } }}</script>
我们在 onselectnode 事件处理函数中判断当前是否已经选中起点节点,如果是则连接当前节点;否则将当前节点设置为起点。在 onunselectnode 事件处理函数中,取消选中节点并重置连接线的信息。
实现节点编辑为了实现节点的编辑,我们需要在 node.vue 中添加一个编辑按钮,并监听它的 click 事件:
<template> <draggable-resizable ...> <div class="node"> <div class="node-content" v-on:click="$emit('edit')"> <!-- 节点的内容 --> </div> <button class="edit-button" v-on:click="$emit('edit')"> 编辑 </button> </div> </draggable-resizable></template><script>export default { name: 'node'}</script><style>.edit-button { position: absolute; bottom: 5px; right: 5px;}</style>
接着,在 flowchart.vue 中监听 edit 事件,在选中的节点上显示一个输入框:
<template> <div class="flowchart"> <div class="nodes"> <!-- 将节点插入到插槽中 --> <slot name="nodes"></slot> </div> <svg class="connections"> <!-- 将连接线插入到插槽中 --> <slot name="connections"></slot> <!-- 鼠标跟随的连接线 --> <connection v-if="showconnection" :start="{x: start.x + start.width / 2, y: start.y + start.height / 2, width: start.width, height: start.height}" :end="{x: end.x + end.width / 2, y: end.y + end.height / 2, width: end.width, height: end.height}"/> </svg> <!-- 编辑区域 --> <div class="edit-panel" v-if="selectednode"> <h3>编辑节点</h3> <form v-on:submit.prevent="savenode"> <label for="node-label">节点名称</label> <input id="node-label" type="text" v-model="nodelabel"> <button type="submit">保存</button> </form> </div> </div></template><script>export default { name: 'flowchart', data () { return { showconnection: false, start: null, // 起点节点 end: null, // 终点节点 selectednode: null, // 选中的节点 nodelabel: '' // 当前节点的标签 } }, methods: { ... onselectnode (node) { // 选中节点时的事件处理函数 if (this.start) { // 已选择起点,连接当前节点 this.end = node this.connectnodes(this.start, this.end) this.selectednode = null } else { // 选择起点 this.start = node } }, onunselectnode () { // 取消选中节点时的事件处理函数 this.start = null this.end = null this.showconnection = false this.selectednode = null }, oneditnode (node) { // 编辑节点时的事件处理函数 this.selectednode = node this.nodelabel = node.$slots.default[0].text.trim() }, savenode () { // 保存节点编辑后的信息 this.selectednode.$slots.default[0].text = this.nodelabel this.selectednode = null } }}</script><style>.edit-panel { position: absolute; top: 0; right: 0; width: 300px; height: 100%; background: #fff; padding: 20px; box-shadow: -1px 0 10px rgba(0, 0, 0, 0.3);}</style>
我们在 onselectnode 事件处理函数中添加了 this.selectednode = null,用于隐藏节点编辑框。在 oneditnode 事件处理函数中,我们向父组件发送了一个 edit 事件,用于显示一个输入框来编辑选中的节点。我们在 savenode 事件处理函数中保存节点编辑后的信息。
导出流程图最后,我们可以在 flowchart.vue 中添加一个导出按钮,将当前流程图导出为 json 格式:
<template> <div class="flowchart"> <div class="nodes"> <!-- 将节点插入到插槽中 --> <slot name="nodes"></slot> </div> <svg class="connections"> <!-- 将连接线插入到插槽中 --> <slot name="connections"></slot> <!-- 鼠标跟随的连接线 --> <connection v-if="showconnection" :start="{x: start.x + start.width / 2, y: start.y + start.height / 2, width: start.width, height: start.height}" :end="{x: end.x + end.width / 2, y: end.y + end.height / 2, width: end.width, height: end.height}"/> </svg> <!-- 编辑区域 --> ... <!-- 导出按钮 --> <button class="export-button" v-on:click="exportflowchart">导出</button> </div></template><script>export default { name: 'flowchart', methods: { ... exportflowchart () { // 导出流程图 const nodes = [] const connections = [] this.$slots.nodes.foreach(vnode => { const node = vnode.componentinstance nodes.push({ x: node.x, y: node.y, width: node.width, height: node.height, label: node.$slots.default[0].text.trim() }) })
以上就是如何使用 vue 实现流程图制作?的详细内容。