Skip to content

自定义边类型 (Custom Edge Types)

yh-flow 支持注册和使用自定义边类型。通过简单的注册机制,您可以为特定类型的连线配置独特的外观与交互逻辑,而无需在每个画布中重复编写代码。

核心概念

在使用自定义组件时,建议优先通过 yh-flow 的 Props 进行注入,这符合低耦合、高内聚的函数式编程思想,且能完美兼容 Nuxt 等 SSR 环境。

1. 组件 Prop 注入 (推荐模式)

通过 edge-types 属性传入一个对象。这种方式作用域明确,不会污染全局状态,是开发复杂应用的首选。

vue
<script setup lang="ts">
import { ref, defineComponent, h } from 'vue'
import { Flow } from '@yh-ui/flow'

// 1. 定义或导入您的自定义边组件
const MyCustomEdge = defineComponent({
  props: ['path', 'stroke'],
  setup(props) {
    return () => h('path', { d: props.path, stroke: 'orange', strokeWidth: 3, fill: 'none' })
  }
})

// 2. 映射到类型字典中
const edgeTypes = {
  'custom-orange': MyCustomEdge
}

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

<template>
  <yh-flow :edges="edges" :edge-types="edgeTypes" />
</template>

2. 全局注册 (多实例共享)

如果您希望在多个不同的画布实例中共享同一组连线样式,可以使用 registerCustomEdge。这会将组件注册到内部的全局注册表中。

CAUTION

SSR (Nuxt 3) 环境下,请通过插件 (Plugin) 仅在客户端执行注册,或优先使用 Prop 注入,以避免跨请求的状态污染。

typescript
import { registerCustomEdge } from '@yh-ui/flow'
// 这里导入您在单独文件中定义的组件
import CustomEdgeComponent from './MyEdge.vue'

registerCustomEdge({
  type: 'my-custom-edge',
  component: CustomEdgeComponent,
  label: '审核流程连线'
})

3. 插槽模式 (手动模式)

如果您只想在特定的画布中临时改变边的样式,或者需要访问复杂的父级上下文,可以使用 #edge 插槽:

vue
<yh-flow :nodes="nodes" :edges="edges">
  <template #edge="edgeProps">
    <!-- 手动控制渲染逻辑 -->
    <MySpecialEdge v-bind="edgeProps" />
  </template>
</yh-flow>

完整示例

开发自定义边组件

自定义组件会接收到包含坐标、路径、中心点以及原始数据在内的完整 Prop 对象。

vue
<!-- CustomEdgeComponent.vue -->
<template>
  <g class="custom-edge" :class="{ 'is-selected': edge.selected }">
    <!-- 绘制主路径 -->
    <path
      :d="path"
      :stroke="stroke"
      :stroke-width="strokeWidth"
      fill="none"
      :stroke-dasharray="edge.animated ? '5,5' : 'none'"
    />

    <!-- 在连线中心添加装饰 -->
    <circle :cx="labelX" :cy="labelY" r="5" fill="#10b981" />

    <!-- 渲染标签 -->
    <text v-if="edge.label" :x="labelX" :y="labelY - 10" text-anchor="middle" class="edge-label">
      {{ edge.label }}
    </text>
  </g>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import type { Edge } from '@yh-ui/flow'

interface Props {
  edge: Edge
  path: string
  sourceX: number
  sourceY: number
  targetX: number
  targetY: number
  labelX: number
  labelY: number
  stroke: string
  strokeWidth: number
}

const props = defineProps<Props>()
</script>

<style scoped>
.custom-edge path {
  transition: all 0.3s;
}
.custom-edge.is-selected path {
  stroke-width: 5;
  filter: drop-shadow(0 0 4px rgba(16, 185, 129, 0.5));
}
.edge-label {
  font-size: 12px;
  fill: #64748b;
  font-weight: bold;
}
</style>

自动渲染演示

下例展示了注册后直接使用 type 属性,EdgeRenderer 如何自动接管渲染。

STREAMING
FINALIZING
数据源
转换层
归档
自动渲染演示

API 参考

策略函数

函数说明
registerCustomEdge(edge: CustomEdge)注册全局自定义边组件
getCustomEdge(type: string)获取注册的组件信息
registerEdgeTemplate(template: EdgeTemplate)注册带有默认数据(如动画、特定颜色)的边模板

类型定义

typescript
// 自定义边配置
interface CustomEdge {
  type: string // 唯一标识,对应 Edge.type
  component: Component // Vue 组件
  label?: string // 别名或描述
}

// 传递给自定义组件的 Props
interface EdgeProps {
  edge: Edge // 原始边数据
  path: string // 根据 type 计算好的 SVG 路径字符串
  sourceX: number // 起点 X
  sourceY: number // 起点 Y
  targetX: number // 终点 X
  targetY: number // 终点 Y
  labelX: number // 默认中心点 X
  labelY: number // 默认中心点 Y
  labelWidth: number // 计算好的标签宽度(px)
  stroke: string // 根据主题或样式计算出的连线颜色
  strokeWidth: number // 计算好的线条宽度
}

所有的自定义边组件必须返回有效的 SVG 元素(通常包装在 <g> 标签中),否则在叠加渲染时会导致图形错乱。

Released under the MIT License.