效果图

代码
<template><div style="width: 100%;height: calc(100vh - 84px)"><VueFlow :nodes="nodes" :edges="edges" @drop="onDrop" @dragover="onDragOver" @dragleave="onDragLeave"><div class="dropzone-background"><Background pattern-color="#aaa" :gap="8" :style="{backgroundColor: isDragOver ? '#e7f3ff' : 'transparent',transition: 'background-color 0.2s ease',}"></Background><div class="overlay"><p v-if="isDragOver">Drop here</p></div></div></VueFlow><Panel position="top-right" class="process-panel"><div class="description">You can drag these nodes to the pane.</div><div class="nodes"><div class="vue-flow__node-input" :draggable="true" @dragstart="onDragStart($event, 'input')">Input Node</div><div class="vue-flow__node-default" :draggable="true" @dragstart="onDragStart($event, 'default')">Default Node</div><div class="vue-flow__node-output" :draggable="true" @dragstart="onDragStart($event, 'output')">Output Node</div></div></Panel></div>
</template><script setup name="Index">
import {ref} from 'vue'
import {VueFlow, Panel, useVueFlow} from '@vue-flow/core'
import {Background} from '@vue-flow/background'
import {MiniMap} from '@vue-flow/minimap'const {onConnect, addEdges, addNodes, toObject, screenToFlowCoordinate, onNodesInitialized, updateNode} = useVueFlow()
const instance = useVueFlow()
const {proxy} = getCurrentInstance();const nodes = ref([]);
const edges = ref([]);
const draggedType = ref(null);
const isDragOver = ref(false);
const isDragging = ref(false);
function onDragStart(event, type) {if (event.dataTransfer) {event.dataTransfer.setData('application/vueflow', type)event.dataTransfer.effectAllowed = 'move'}draggedType.value = typeisDragging.value = truedocument.addEventListener('drop', onDragEnd)
}
function onDragOver(event) {event.preventDefault()if (draggedType.value) {isDragOver.value = trueif (event.dataTransfer) {event.dataTransfer.dropEffect = 'move'}}
}
function onDrop(event) {const position = screenToFlowCoordinate({x: event.clientX,y: event.clientY,})const nodeId = Math.random() + "id";const newNode = {id: nodeId,type: draggedType.value,position,data: {label: nodeId},}const {off} = onNodesInitialized(() => {updateNode(nodeId, (node) => ({position: {x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2},}))off()})addNodes(newNode)
}
function onDragLeave() {isDragOver.value = false
}
function onDragEnd() {isDragging.value = falseisDragOver.value = falsedraggedType.value = nulldocument.removeEventListener('drop', onDragEnd)
}onConnect(addEdges)
</script><style>
@import '@vue-flow/core/dist/style.css';
@import '@vue-flow/core/dist/theme-default.css';.process-panel {background-color: #EBEEF5;padding: 10px;border-radius: 8px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);display: flex;flex-direction: column;
}.dropzone-background {position: relative;height: 100%;width: 100%
}.dropzone-background .overlay {position: absolute;top: 0;left: 0;height: 100%;width: 100%;display: flex;align-items: center;justify-content: center;z-index: 1;pointer-events: none
}
</style>