Skip to content

边简介

🌐 Introduction to Edges

边是连接节点的链接,形成一张地图。每条边从一个控制点连接到另一个控制点,并且可以根据你的喜好进行自定义。

🌐 Edges are the links connecting your nodes, forming a map. Each edge runs from one handle to another, and can be customized to your liking.

记住,每一条边都是独一无二的,因此需要一个唯一的ID、一个源节点ID和一个目标节点ID。

🌐 Remember, every edge is unique and thus requires a unique id, a source and target node id.

有关边缘可用选项的完整列表,请查看 边缘类型

🌐 For the full list of options available for an edge, check out the Edge Type.

向图中添加边

🌐 Adding Edges to the Graph

边缘通过将它们传递给 Vue Flow 组件的 edges 属性(或已弃用的 v-model 属性)来渲染。

🌐 Edges are rendered by passing them to the edges prop (or the deprecated v-model prop) of the Vue Flow component.

WARNING

此方法不会产生任何更改。有关更多信息,请查看受控流程部分。

vue

<script setup>
import { ref, onMounted } from 'vue'
import { VueFlow } from '@vue-flow/core'

const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  }
]);

const edges = ref([
  {
    id: 'e1->2',
    source: '1',
    target: '2',
  }
]);
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges" />
</template>
vue

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import type { Node, Edge } from '@vue-flow/core'
import { VueFlow } from '@vue-flow/core'

const nodes = ref<Node[]>([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  }
]);

const edges = ref<Edge[]>([
  {
    id: 'e1->2',
    source: '1',
    target: '2',
  }
]);
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges" />
</template>

如果你正在处理更复杂的图表,或者只是需要访问内部状态,useVueFlow 组合函数将非常有用。

🌐 If you are working with more complex graphs or simply require access to the internal state, the useVueFlow composable will come in handy.

通过 useVueFlow 可以使用 addEdges 操作,允许你直接向状态添加边。

🌐 The addEdges action is available through useVueFlow, allowing you to add edges straight to the state.

此外,这个操作不仅限于渲染图表的组件;它也可以在其他地方使用,比如侧边栏或工具栏。

🌐 What's more, this action isn't limited to the component rendering the graph; it can be utilized elsewhere, like in a Sidebar or Toolbar.

vue
<script setup>
import { VueFlow, useVueFlow } from '@vue-flow/core'

const initialNodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  }
])

const { addEdges } = useVueFlow()

addEdges([
  {
    source: '1',
    target: '2',

    // if a node has multiple handles of the same type,
    // you should specify which handle to use by id
    sourceHandle: null,
    targetHandle: null,
  }
])
</script>

<template>
  <VueFlow :nodes="initialNodes" />
</template>

从图表中移除边

🌐 Removing Edges from the Graph

类似于添加边,可以通过从 mode-value(使用 v-model)或 Vue Flow 组件的 edges 属性中移除边,从而从图中删除边。

🌐 Similar to adding edges, edges can be removed from the graph by removing them from the mode-value (using v-model) or from the edges prop of the Vue Flow component.

vue
<script setup>
import { ref, onMounted } from 'vue'
import { VueFlow, Panel } from '@vue-flow/core'

const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  },
]);

const edges = ref([
  {
    id: 'e1->2',
    source: '1',
    target: '2',
  }
]);

function removeEdge(id) {
  edges.value = edges.value.filter((edge) => edge.id !== id)
}
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges">
    <Panel>
      <button @click="removeEdge('e1->2')">Remove Edge</button>
    </Panel>
  </VueFlow>
</template>

通过 useVueFlow 可以使用 removeEdges 操作,允许你直接从状态中移除边。

🌐 The removeEdges action is available through useVueFlow, allowing you to remove edges straight from the state.

你还可以在渲染图表的组件外部使用此操作,例如在侧边栏或工具栏中。

🌐 You can also use this action outside the component rendering the graph, like in a Sidebar or Toolbar.

vue
<script setup>
import { ref, onMounted } from 'vue'  
import { VueFlow, useVueFlow } from '@vue-flow/core'

const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  },
  {
    id: '3',
    position: { x: 250, y: 50 },
    data: { label: 'Node 3', },
  },
  {
    id: '4',
    position: { x: 250, y: 250 },
    data: { label: 'Node 4', },
  },
])

const edges = ref([
  {
    id: 'e1->2',
    source: '1',
    target: '2',
  },
  {
    id: 'e1->3',
    source: '1',
    target: '3',
  },
  {
    id: 'e2->3',
    source: '2',
    target: '3',
  },
  {
    id: 'e2->4',
    source: '2',
    target: '4',
  },
])

const { removeEdges } = useVueFlow()

function removeOneEdge() {
  removeEdges('e1->2')
}

function removeMultipleEdges() {
  removeEdges(['e1->3', 'e2->3'])
}
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges">
    <Panel>
      <button @click="removeOneEdge">Remove Edge 1</button>
      <button @click="removeMultipleEdges">Remove Edges 2 and 3</button>
    </Panel>
  </VueFlow>
</template>

更新边数据

🌐 Updating Edge Data

由于边是反应性的对象,你可以随时通过修改它来更新其数据。这使你可以在任何时间更改标签,甚至向数据对象添加新的属性。

🌐 Since edges are reactive object, you can update their data at any point by simply mutating it. This allows you to change the label, or even add new properties to the data object at any point in time.

实现此目的的方法有很多,以下是一些示例:

🌐 There are multiple ways of achieving this, here are some examples:

ts
import  { useVueFlow } from '@vue-flow/core'

const instance = useVueFlow()

// use the `updateEdgeData` method to update the data of an edge
instance.updateEdgeData(edgeId, { hello: 'mona' })

// find the edge in the state by its id
const edge = instance.findEdge(edgeId)

edge.data = {
  ...edge.data,
  hello: 'world',
}

// you can also mutate properties like `selectable` or `animated`
edge.selectable = !edge.selectable
edge.animated = !edge.animated
vue
<!-- CustomEdge.vue -->
<script setup>
import { useEdge } from '@vue-flow/core'

// `useEdge` returns us the edge object straight from the state
// since the edge obj is reactive, we can mutate it to update our edges' data
const { edge } = useEdge()

function onSomeEvent() {
  edge.data = {
    ...edge.data,  
    hello: 'world',
  }
  
  // you can also mutate properties like `selectable` or `animated`
  edge.selectable = !edge.selectable
  edge.animated = !edge.animated
}
</script>
vue
<script setup>
import { ref } from 'vue'

const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: {
      label: 'Node 1',
      hello: 'world',
    },
  },
  {
      id: '2',
      position: { x: 50, y: 250 },
      data: { label: 'Node 2', },
  },
])

const edges = ref([
  {
    id: 'e1->2',
    source: '1',
    target: '2',
  },
])

function onSomeEvent(edgeId) {
  const edge = edges.value.find((edge) => edge.id === edgeId)
  edge.data = {
    ...elements.value[0].data,
    hello: 'world',
  }

  // you can also mutate properties like `selectable` or `animated`
  edge.selectable = !edge.selectable
  edge.animated = !edge.animated
}
</script>

<template>
  <VueFlow v-model="elements" />
</template>

预定义边类型

🌐 Predefined Edge-Types

Vue Flow 提供了几种内置的边类型,你可以立即使用。包含的节点类型有 default(贝塞尔曲线)、stepsmoothstepstraight

🌐 Vue Flow provides several built-in edge types that you can leverage immediately. The included node types are default (bezier), step, smoothstep and straight.

默认边(贝塞尔曲线)

🌐 Default Edge (Bezier)

默认边是连接两个节点的贝塞尔曲线。

🌐 The default edge is a bezier curve that connects two nodes.

步进边

🌐 Step Edge

步进边具有一条直线路径,并朝着目标迈进。

🌐 A step edge has a straight path with a step towards the target.

平滑步进边

🌐 Smoothstep Edge

与台阶边缘相同,但台阶上有边框半径(圆角台阶)。

🌐 The same as the step edge though with a border radius on the step (rounded step).

直边

🌐 Straight Edge

一条简单的直线路径。

🌐 A simple straight path.

用户定义边

🌐 User-Defined Edges

除了前面提到的默认边类型之外,你可以根据需要创建任意多的自定义边类型。边类型是根据你的边定义来确定的。

🌐 On top of the default edge types mentioned earlier, you can create as many custom edge-types as you need. Edge-types are determined from your edges' definitions.

vue
<script setup>
import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core'

import CustomEdge from './CustomEdge.vue'
import SpecialEdge from './SpecialEdge.vue'

export const edges = ref([
  {
    id: 'e1->2',
    source: '1',
    target: '2',
    // this will create the edge-type `custom`
    type: 'custom',
  },
  {
    id: 'e1->3',
    source: '1',
    target: '3',
    // this will create the edge-type `special`
    type: 'special',
  }
])
  
const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  },
  {
    id: '3',
    position: { x: 250, y: 50 },
    data: { label: 'Node 3', },
  },
  {
    id: '4',
    position: { x: 250, y: 250 },
    data: { label: 'Node 4', },
  },
])
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges">
    <template #edge-custom="customEdgeProps">
      <CustomEdge v-bind="customEdgeProps" />
    </template>
    
    <template #edge-special="specialEdgeProps">
      <SpecialEdge v-bind="specialEdgeProps" />
    </template>
  </VueFlow>
</template>
vue
<script setup>
import { BezierEdge } from '@vue-flow/core';

// props were passed from the slot using `v-bind="customEdgeProps"`
const props = defineProps(['sourceX', 'sourceY', 'targetX', 'targetY', 'sourcePosition', 'targetPosition']);
</script>

<script lang="ts">
export default {
  name: 'CustomEdge',
};
</script>

<template>
  <BezierEdge
      :source-x="sourceX"
      :source-y="sourceY"
      :target-x="targetX"
      :target-y="targetY"
      :source-position="sourcePosition"
      :target-position="targetPosition"
  />
</template>
vue
<script setup lang="ts">
import { ref } from 'vue'
import type { Edge } from '@vue-flow/core'
import { VueFlow } from '@vue-flow/core'

import CustomEdge from './CustomEdge.vue'
import SpecialEdge from './SpecialEdge.vue'

// You can pass 3 optional generic arguments to the Edge type, allowing you to define:
// 1. The data object type
// 2. The events object type
// 3. The possible edge types

interface CustomData {
    hello: string
}

type CustomEdgeTypes = 'custom' | 'special'

type CustomEdge = Edge<CustomData, any, CustomEdgeTypes>

export const edges = ref<CustomEdge[]>([
    {
      id: 'e1-2',
      source: '1',
      target: '2',
      // this will create the edge-type `custom`
      type: 'custom',
    },
    {
      id: 'e1-3',
      source: '1',
      target: '3',
      // this will create the edge-type `special`
      type: 'special',
    },
    
    {
      id: 'e1-4',
      source: '1',
      target: '4',
      // this will throw a type error, as the type is not defined in the CustomEdgeTypes
      // regardless it would be rendered as a default edge type
      type: 'not-defined',
    }
])
  
const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  },
  {
    id: '3',
    position: { x: 250, y: 50 },
    data: { label: 'Node 3', },
  },
  {
    id: '4',
    position: { x: 250, y: 250 },
    data: { label: 'Node 4', },
  },
])  
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges">
    <template #edge-custom="customEdgeProps">
      <CustomEdge v-bind="customEdgeProps" />
    </template>
    
    <template #edge-special="specialEdgeProps">
      <SpecialEdge v-bind="specialEdgeProps" />
    </template>
  </VueFlow>
</template>
vue
<script setup lang="ts">
import type { EdgeProps } from '@vue-flow/core';
import { BezierEdge } from '@vue-flow/core';

import { CustomData } from './edges'

// props were passed from the slot using `v-bind="customEdgeProps"`
const props = defineProps<EdgeProps<CustomData>>();

console.log(props.data.hello) // 'world'
</script>

<script lang="ts">
export default {
  name: 'CustomEdge',
};
</script>

<template>
  <BezierEdge
      :source-x="sourceX"
      :source-y="sourceY"
      :target-x="targetX"
      :target-y="targetY"
      :source-position="sourcePosition"
      :target-position="targetPosition"
  />
</template>

Vue Flow 接着会尝试将此边类型解析为一个组件。优先使用状态的 edgeTypes 对象中的定义。接下来,它会尝试将组件与同名的全局注册组件进行匹配。最后,它会搜索提供的模板插槽来填充该边类型。

🌐 Vue Flow will then attempt to resolve this edge-type to a component. Priority is given to a definition in the edgeTypes object of the state. Next, it tries to match the component to a globally registered one with the same name. Finally, it searches for a provided template slot to fill in the edge-type.

如果在解析组件时没有任何方法产生结果,则使用默认边类型作为后备。

🌐 If no methods produce a result in resolving the component, the default edge-type is used as a fallback.

模板插槽

🌐 Template slots

定义自定义边缘的最简单方法之一是通过将它们作为模板槽传递。对槽名称的动态解析是为你定义的边缘类型完成的,这意味着类型为 custom 的边缘预计会有一个名为 #edge-custom 的槽。

🌐 One of the easiest ways to define custom edges is, by passing them as template slots. Dynamic resolution to slot-names is done for your user-defined edge-types, meaning a edge with the type custom is expected to have a slot named #edge-custom.

vue
<script setup>
import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core'
import CustomEdge from './CustomEdge.vue'

const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  },
])

const edges = ref([
  {
    id: 'e1->2',
    type: 'custom',
    source: '1',
    target: '2',
  },
])
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges">
    <template #edge-custom="props">
      <CustomEdge v-bind="props" />
    </template>
  </VueFlow>
</template>

边缘类型对象

🌐 Edge-types object

或者,也可以通过将对象作为 prop 传递给 VueFlow 组件(或作为可组合项的选项)来定义边缘类型。

🌐 Alternatively, edge-types can also be defined by passing an object as a prop to the VueFlow component (or as an option to the composable).

WARNING

采取预防措施,将你的组件标记为原始(使用 Vue 库中的 mark 函数)以防止它们被转换为响应式对象。否则,Vue 会在控制台显示警告。

vue
<script setup>
import { markRaw } from 'vue'
import CustomEdge from './CustomEdge.vue'

const edgeTypes = {
  custom: markRaw(CustomEdge),
}

const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  },
])

const edges = ref([
  {
    id: 'e1->2',
    type: 'custom',
    source: '1',
    target: '2',
  },
])
</script>
<template>
  <VueFlow :nodes="nodes" :edges="edges" :edgeTypes="edgeTypes" />
</template>

边缘属性

🌐 Edge Props

你的自定义边已被封装,以便像选择这样的基本功能能够正常运作。但你可能希望扩展这些功能,或在边中实现你的业务逻辑,因此你的边将接收以下属性:

🌐 Your custom edges are enclosed so that fundamental functions like selecting operate. But you may wish to expand on these features or implement your business logic inside edges, thus your edges receive the following properties:

属性名称描述类型可选
id唯一边缘IDstring
sourceNode源节点图节点
targetNode目标节点图节点
source源节点的IDstring
target目标节点的IDstring
type边缘类型string
label边缘标签,可以是字符串或 VNode字符串VNode
styleCSS 属性CSS属性
selected边已选择boolean
sourcePosition源位置位置
targetPosition目标位置位置
sourceHandleId源句柄的IDstring
targetHandleId目标句柄的IDstring
animatedEdge 是否有动画boolean
updatable可以更新边缘boolean
markerStart开始标记string
markerEnd结束标记string
curvature边缘的曲率number
interactionWidth边缘交互区域的宽度number
data边的附加数据任何对象
events边缘的上下文和自定义事件边缘事件开启

边事件

🌐 Edge Events

Vue Flow 提供了两种监听边缘事件的主要方式:可以使用 useVueFlow 将监听器绑定到事件处理程序,或者将它们绑定到 <VueFlow> 组件。

🌐 Vue Flow provides two main ways of listening to edge events, either by using useVueFlow to bind listeners to the event handlers or by binding them to the <VueFlow> component.

vue
<script setup>
import { ref } from 'vue'  
import { VueFlow, useVueFlow } from '@vue-flow/core'

// useVueFlow provides access to the event handlers
const { 
  onEdgeClick,
  onEdgeDoubleClick,
  onEdgeContextMenu,
  onEdgeMouseEnter,
  onEdgeMouseLeave,
  onEdgeMouseMove,
  onEdgeUpdateStart,
  onEdgeUpdate,
  onEdgeUpdateEnd,
} = useVueFlow()
  
const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  },
])

const edges = ref([
  {
    id: 'e1->2',
    source: '1',
    target: '2',
  },
])
  
// bind listeners to the event handlers
onEdgeClick((event, edge) => {
  console.log('edge clicked', edge)
})

onEdgeDoubleClick((event, edge) => {
  console.log('edge double clicked', edge)
})

onEdgeContextMenu((event, edge) => {
  console.log('edge context menu', edge)
})
  
// ... and so on  
</script>

<template>
  <VueFlow :nodes="nodes" :edges="edges" />
</template>
vue
<script setup>
import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core'

const nodes = ref([
  {
    id: '1',
    position: { x: 50, y: 50 },
    data: { label: 'Node 1', },
  },
  {
    id: '2',
    position: { x: 50, y: 250 },
    data: { label: 'Node 2', },
  },
])

const edges = ref([
  {
    id: 'e1->2',
    source: '1',
    target: '2',
  },
])
  
function logEvent(eventName, data) {
  console.log(eventName, data)
}
</script>

<template>
  <VueFlow
    :nodes="nodes"
    :edges="edges"
    @edge-click="logEvent('edge clicked', $event)"
    @edge-double-click="logEvent('edge double clicked', $event)"
    @edge-context-menu="logEvent('edge context menu', $event)"
    @edge-mouse-enter="logEvent('edge mouse enter', $event)"
    @edge-mouse-leave="logEvent('edge mouse leave', $event)"
    @edge-mouse-move="logEvent('edge mouse move', $event)"
    @edge-update-start="logEvent('edge update start', $event)"
    @edge-update="logEvent('edge update', $event)"
    @edge-update-end="logEvent('edge update end', $event)"
  />
</template>

互动以在浏览器控制台查看事件

<Background class="rounded-lg" />

自定义外观

🌐 Customizing Appearance

TIP

要覆盖默认主题的样式,请访问主题部分

VueFlow 中文网 - 粤ICP备13048890号