组件/Flowchart 流程画布

Flowchart 流程画布

点阵画布上的工作流节点:分类胶囊、卡片插槽、自动贝塞尔连线,可拖拽且始终受控。

已验证自 0.6.0

用法

Flowchart

订单工作流

触发器与条件分支两个节点,连线随卡片高度自动重算;按住卡片可以拖动,落点吸附到点阵。

示例加载中...

最佳实践

  • 同一条流水线上的节点写同一个 x,让连线退化成直线。
  • 卡片内容自己控制高度,不要给卡片写死 height——连线是按实测高度画的,写死会让两者对不上。
  • 分类胶囊的 tone 表达的是步骤种类(触发、分支、动作),不是状态,所以它用的是 BUI 的强调色集而不是 --tx-* 语义色阶。

API 参考

Props

属性名类型默认值说明
nodesFlowNode[]—画布上的节点。必填。
edgesFlowEdge[][]节点间的连线。
heightnumber333画布高度(px)。
nodeWidthnumber290节点默认宽度,可被 FlowNode.width 覆盖。
gridnumber22点阵间距,同时是拖拽吸附步长。
dotsbooleantrue是否绘制点阵。
draggablebooleanfalse是否允许拖拽节点。
snapbooleantrue拖拽时是否吸附到点阵。
ariaLabelstring'Workflow'画布区域的无障碍名称。

FlowNode 的字段:id、x、y 必填;label 是卡片上方的分类胶囊,tone 取 violet / orange / accent / green / red / neutral;width 覆盖单个节点宽度;draggable 单独关掉某个节点的拖拽。

Events

事件名回调参数说明
node-move{ id, x, y }某个节点拖拽结束。组件不会改 nodes,宿主要自己写回去这次移动才会留下。
node-click{ id, node }节点被点击、或在聚焦时按下 Enter / 空格。

Slots

插槽名作用域参数说明
node{ node, index }卡片内容。不传则渲染一张空卡。
label{ node }替换卡片上方的分类胶囊。

坐标系

x 是节点的水平中心,不是左边缘——节点用 translateX(-50%) 骑在这条中线上,所以同一条竖直流水线上的节点写同一个 x 就能对齐,不用先知道卡片有多宽。y 是上边缘。两者都是画布内的 CSS 像素。

grid 同时是点阵间距和拖拽吸附的步长,默认 22px。点阵用 radial-gradient 画:圆点落在 1px、渐隐到 1.25px。硬停在 1px 会在栅格尺寸上锯齿成方块,超过约 1.5px 又会变成和卡片抢视线的纹理。

连线

edges 里的每条连线从 from 的下边缘画到 to 的上边缘。卡片高度由内容决定——两行条件比一行触发器高——所以组件用 ResizeObserver 实测每张卡的高度再算路径,而不是假设一个值把线头画进卡片里或者悬在卡片下方。

曲线的两个控制点都越过中点并且交叉(各偏 0.55 倍垂距)。竖直对齐的一对因此读作直线,而横向错开的一对仍然是垂直进出卡片,不会像 0.5 那样松垮。

指向画布上不存在的节点的连线会被跳过,不会画到原点——否则一条线会横穿整个画布。

概述

  • 始终受控。 组件不写 nodes。拖拽过程中它在内部记一个临时偏移让卡片跟手,松手时清掉偏移并发出 node-move;宿主不写回,节点就弹回原位。这一点是刻意的:撤销栈、吸附到别的规则、服务端持久化都应该由宿主决定。
  • 可拖拽节点带 touch-action: none。 否则触摸拖拽会变成滚动页面。
  • 节点可聚焦。 每个节点是 Tab 停靠点,Enter / 空格触发 node-click,焦点环由 :focus-visible 给出。
  • 连线画在卡片下方,这样卡片的发丝环阴影会盖住线头,而不是让线横穿卡片圆角。

技术实现

  • 组件源码:packages/tuffex/packages/components/src/flowchart/src/TxFlowchart.vue。
  • 类型:packages/tuffex/packages/components/src/flowchart/src/types.ts。
  • 移植自 Beautiful UI(https://www.beautifului.dev)第 16 例 Flowchart,© 2026 Shane Levine,MIT。
查看源码
packages/tuffex/packages/components/src/flowchart/index.ts