无法连接拖放自定义节点

问题描述 投票:0回答:1

在使用 vueflow 包和各种示例(drag-n-drop自定义节点)时,我很难连接自定义节点。一些使用的组件来自Vuetify

StartNode 按预期呈现。将 InputNode 从侧面拖到 VueFlow 中也可以按预期工作。但随后问题就开始了。有多个问题,但也许一个可以回答另一个问题,如果没有,我会问另一个问题。从 StartNode 拖动到 InputNode 时出现以下错误:

错误:

<path>
属性 d:预期数量

从 InputNode 拖动到 StartNode 时,不会给出错误,但会渲染一个新的“默认节点”。

我希望有人能为我指出如何连接自定义节点的正确方向。

主文件

<template>
    <v-row>
        <v-col cols="9" style="height: 500px" @drop="onDrop">
            <VueFlow
                v-model:nodes="nodes"
                v-model:edges="edges"
                :node-types="types"
                :connection-mode="ConnectionMode.Strict"
                @dragover="onDragOver"
                @dragleave="onDragLeave"
            />
        </v-col>

        <v-col cols="3">
            <InputNode
                :draggable="true"
                @dragstart="onDragStart( $event, 'input' )"
            />
        </v-col>
    </v-row>
</template>

<script setup>
import { ref, markRaw } from 'vue';
import { VueFlow, useVueFlow, ConnectionMode } from '@vue-flow/core';
import useDragAndDrop from './drag-n-drop.js';
import StartNode from './nodes/StartNode.vue';
import InputNode from './nodes/InputNode.vue';

const { onConnect, addEdges } = useVueFlow();

const { onDragOver, onDrop, onDragLeave, onDragStart } = useDragAndDrop()

const nodes = ref( [
    {
        id: 'start-node',
        type: 'start',
        position: { x: 0, y: 50 },
        dimensions: { width: '150px', height: '50px' },
    },
] );

const edges = ref( [] );

const types = {
    start: markRaw( StartNode ),
    input: markRaw( InputNode ),
};

onConnect( addEdges );
</script>

<style>
@import '@vue-flow/core/dist/style.css';
@import '@vue-flow/core/dist/theme-default.css';
</style>

起始节点:

<template>
    <div>
        <v-card color="green" :width="props.dimensions?.width ?? '150px'" :height="props.dimensions?.height ?? '50px'">
            <v-card-text>Start</v-card-text>

        </v-card>
        <Handle id="start" type="source" :position="Position.Right" :connectable="handleConnectable" />
    </div>
</template>

<script setup>
import { Position, Handle } from '@vue-flow/core';

const props = defineProps( {
    id: {
        type: String,
        required: true,
    },
    data: {
        type: Object,
        required: true,
    },

    dimensions: {
        type: Object,
        required: false,
    },
} );

function handleConnectable( node, connectedEdges )
{
    return connectedEdges.length <= 1;
}
</script>

输入节点:

<template>
    <div
    >
        <Handle v-if="data" id="input-target" type="target" :position="Position.Right" :connectable="handleConnectable" />

        <v-card
            :draggable="props.draggable"
            :width="'300px'"
            :height="'104px'"
        >

            <v-card-title>Input</v-card-title>

            <v-card-text>
                <v-text-field
                    label="Input"
                    outlined
                    hide-details
                    density="compact"
                />
            </v-card-text>

        </v-card>

        <Handle v-if="data" id="input-source" type="source" :position="Position.Left" :connectable="handleConnectable" />
    </div>
</template>

<script setup>
import { Handle, Position } from '@vue-flow/core';

const props = defineProps( {
    id: {
        type: String,
        required: false,
    },

    data: {
        type: Object,
        required: false,
    },

    dimensions: {
        type: Object,
        required: false,
    },

    draggable: {
        type: Boolean,
        required: false,
        default: true,
    },
} );

function handleConnectable( node, connectedEdges )
{
    return connectedEdges.length <= 1;
}
</script>

drag-n-drop.js(取自示例):

import { useVueFlow } from '@vue-flow/core'
import { ref, watch } from 'vue'

let id = 0

/**
 * @returns {string} - A unique id.
 */
function getId() {
  return `dndnode_${id++}`
}

/**
 * In a real world scenario you'd want to avoid creating refs in a global scope like this as they might not be cleaned up properly.
 * @type {{draggedType: Ref<string|null>, isDragOver: Ref<boolean>, isDragging: Ref<boolean>}}
 */
const state = {
  /**
   * The type of the node being dragged.
   */
  draggedType: ref(null),
  isDragOver: ref(false),
  isDragging: ref(false),
}

export default function useDragAndDrop() {
  const { draggedType, isDragOver, isDragging } = state

  const { addNodes, screenToFlowCoordinate, onNodesInitialized, updateNode } = useVueFlow()

  watch(isDragging, (dragging) => {
    document.body.style.userSelect = dragging ? 'none' : ''
  })

  function onDragStart(event, type) {
    if (event.dataTransfer) {
      event.dataTransfer.setData('application/vueflow', type)
      event.dataTransfer.effectAllowed = 'move'
    }

    draggedType.value = type
    isDragging.value = true

    document.addEventListener('drop', onDragEnd)
  }

  /**
   * Handles the drag over event.
   *
   * @param {DragEvent} event
   */
  function onDragOver(event) {
    event.preventDefault()

    if (draggedType.value) {
      isDragOver.value = true

      if (event.dataTransfer) {
        event.dataTransfer.dropEffect = 'move'
      }
    }
  }

  function onDragLeave() {
    isDragOver.value = false
  }

  function onDragEnd() {
    isDragging.value = false
    isDragOver.value = false
    draggedType.value = null
    document.removeEventListener('drop', onDragEnd)
  }

  /**
   * Handles the drop event.
   *
   * @param {DragEvent} event
   */
  function onDrop(event) {
    const position = screenToFlowCoordinate({
      x: event.clientX,
      y: event.clientY,
    })

    const nodeId = getId()

    const newNode = {
      id: nodeId,
      type: draggedType.value,
      position,
      data: { label: nodeId },
    }

    /**
     * Align node position after drop, so it's centered to the mouse
     *
     * We can hook into events even in a callback, and we can remove the event listener after it's been called.
     */
    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)
  }

  return {
    draggedType,
    isDragOver,
    isDragging,
    onDragStart,
    onDragLeave,
    onDragOver,
    onDrop,
  }
}

javascript vue.js vuejs3
1个回答
0
投票

有几个问题。第一个问题是句柄源和目标位置交换了。

StartNode
中的第二期是动态
width
height

第三个问题是在

InputNode
上,
:draggable="props.draggable"
上声明的
v-card
导致了添加默认节点的问题。

© www.soinside.com 2019 - 2024. All rights reserved.