vite+elementPlus+vue3+jsplumb+pinia+sortable实现完整的流程图
时间: 2023-09-02 07:14:11 浏览: 174
实现完整的流程图需要以下步骤:
1. 安装依赖
```
npm install vite vue@next element-plus @vueuse/core jsplumb pinia sortablejs
```
2. 创建组件
在src/components目录下创建FlowChart.vue组件:
```html
<template>
<div class="flow-chart">
<div class="chart-container">
<div class="chart"></div>
</div>
</div>
</template>
<script>
import { defineComponent, ref, watchEffect } from 'vue'
import { useRoute } from 'vue-router'
import { useStore } from 'pinia'
import Sortable from 'sortablejs'
import jsPlumb from 'jsplumb'
import 'jsplumb/dist/js/jsplumb.min.css'
export default defineComponent({
name: 'FlowChart',
setup() {
const store = useStore()
const route = useRoute()
const chartInstance = ref(null)
watchEffect(() => {
drawChart()
})
function drawChart() {
const chart = document.querySelector('.chart')
chart.innerHTML = ''
const nodes = store.state.nodes.filter(
(node) => node.page === route.name
)
const instance = jsPlumb.getInstance({
Container: chart,
Connector: ['Straight', { gap: 5 }],
Endpoint: ['Dot', { radius: 4 }],
EndpointStyle: { fill: 'transparent', stroke: '#555' },
PaintStyle: { stroke: '#555', strokeWidth: 2 },
DragOptions: { cursor: 'pointer', zIndex: 2000 },
ConnectionOverlays: [
[
'Arrow',
{
location: 1,
visible: true,
width: 11,
length: 11,
id: 'ARROW',
},
],
],
})
nodes.forEach((node) => {
const el = document.createElement('div')
el.classList.add('node')
el.setAttribute('id', node.id)
el.style.top = node.top + 'px'
el.style.left = node.left + 'px'
el.innerHTML = node.label
chart.appendChild(el)
instance.draggable(el, {
stop: (event) => {
const top = parseInt(event.el.style.top)
const left = parseInt(event.el.style.left)
store.updateNode(node.id, { top, left })
},
})
})
nodes.forEach((node) => {
const connections = store.state.connections.filter(
(conn) => conn.source === node.id
)
connections.forEach((conn) => {
instance.connect({
source: node.id,
target: conn.target,
overlays: [['Arrow', { location: 1, width: 11, length: 11 }]],
})
})
})
chartInstance.value = instance
}
return {
chartInstance,
}
},
})
</script>
<style scoped>
.flow-chart {
width: 100%;
height: 100%;
}
.chart-container {
position: relative;
width: 100%;
height: 100%;
overflow: auto;
}
.chart {
position: absolute;
top: 0;
left: 0;
width: 10000px;
height: 10000px;
}
.node {
position: absolute;
width: 100px;
height: 40px;
background-color: #fff;
border: 1px solid #ccc;
text-align: center;
line-height: 40px;
cursor: pointer;
}
</style>
```
3. 创建路由
在src/router/index.js中添加路由:
```js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import FlowChart from '../components/FlowChart.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home,
},
{
path: '/flow-chart',
name: 'FlowChart',
component: FlowChart,
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
})
export default router
```
4. 创建状态管理
在src/store/index.js中创建状态管理:
```js
import { defineStore } from 'pinia'
export const useFlowChartStore = defineStore('flow-chart', {
state: () => ({
nodes: [],
connections: [],
}),
actions: {
addNode(node) {
node.id = Date.now().toString()
node.top = 100
node.left = 100
this.nodes.push(node)
},
updateNode(nodeId, data) {
const node = this.nodes.find((node) => node.id === nodeId)
if (node) {
Object.assign(node, data)
}
},
addConnection(connection) {
this.connections.push(connection)
},
removeNode(nodeId) {
this.nodes = this.nodes.filter((node) => node.id !== nodeId)
this.connections = this.connections.filter(
(conn) => conn.source !== nodeId && conn.target !== nodeId
)
},
removeConnection(connection) {
this.connections = this.connections.filter(
(conn) =>
conn.source !== connection.source || conn.target !== connection.target
)
},
},
})
```
5. 创建视图
在src/views/Home.vue中创建视图:
```html
<template>
<div class="home">
<div class="sidebar">
<form @submit.prevent="addNode">
<label>
Label:
<input type="text" v-model="label" />
</label>
<button>Add Node</button>
</form>
<ul>
<li v-for="node in nodes" :key="node.type">
{{ node.label }}
<button @click="removeNode(node.id)">Remove</button>
</li>
</ul>
</div>
<div class="main">
<router-view />
</div>
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
import { useFlowChartStore } from '../store'
export default defineComponent({
name: 'Home',
setup() {
const store = useFlowChartStore()
const label = ref('')
const nodes = ref([
{ type: 'start', label: 'Start' },
{ type: 'end', label: 'End' },
{ type: 'task', label: 'Task' },
{ type: 'decision', label: 'Decision' },
])
function addNode() {
store.addNode({ type: 'task', label: label.value })
label.value = ''
}
function removeNode(nodeId) {
store.removeNode(nodeId)
}
return {
label,
nodes,
addNode,
removeNode,
}
},
})
</script>
<style scoped>
.home {
display: flex;
flex-direction: row;
height: 100%;
}
.sidebar {
width: 200px;
padding: 20px;
background-color: #f5f5f5;
}
.main {
flex: 1;
height: 100%;
}
</style>
```
6. 运行应用
在package.json中添加运行命令:
```json
{
"scripts": {
"dev": "vite"
}
}
```
运行应用:
```
npm run dev
```
应用运行后,打开http://localhost:3000/,就可以看到一个空的流程图页面。在侧边栏添加节点,然后拖动节点到画布中,连接节点,就可以完成一个简单的流程图。
阅读全文