- 前端
- UI组件
【免费下载链接】vue-flow
A highly customizable Flowchart component for Vue 3. Features seamless zoom & pan 🔎, additional components like a Minimap 🗺 and utilities to interact with state and graph.
@vue-flow/node-toolbar是 Vue Flow(Vue 3 流程图库)官方扩展包,提供与节点绑定的浮动工具栏组件。本文从安装配置、Props 与 Slots 用法、可见性控制、定位算法到源码级实现原理,完整讲解如何在节点旁快速构建可交互的操作工具栏,并带你理解其与 Vue Flow 核心的协作机制。
包概述与定位
NodeToolbar 是 Vue Flow 生态中的官方插件之一,仓库位于packages/node-toolbar。其核心定位是:在节点旁边创建一个浮动的工具栏,用于承载删除、复制、展开等节点级操作按钮,或在用户选中节点时自动浮现操作入口。
从包结构看(src/index.ts),该包对外只导出两个东西:
NodeToolbar组件(即NodeToolbar.vue)NodeToolbarProps等类型定义(src/types.ts)
包本身不包含 Vue Flow 核心代码,仅声明了 peer 依赖(package.json):
@vue-flow/core:^1.23.0vue:^3.3.0
这意味着使用 NodeToolbar 的前提是项目中已安装 Vue 3 与 Vue Flow 核心。
安装与依赖
安装命令
# 使用 yarn yarn add @vue-flow/node-toolbar # 或使用 npm npm install @vue-flow/node-toolbar@vue-flow/node-toolbar当前版本为 1.1.1(见 CHANGELOG.md)。
与核心包的版本匹配
NodeToolbar 使用 Vue Flow 核心的useVueFlow、Position枚举、NodeIdInjection(节点上下文注入)等 API,因此必须与核心包版本保持兼容。仓库的 peer 依赖声明为^1.23.0,实际使用时应确保@vue-flow/core与@vue-flow/node-toolbar版本匹配。
快速上手:把工具栏挂到自定义节点上
NodeToolbar 通常是在自定义节点的模板内部使用的,通过插槽与节点上下文自动关联到当前节点。
第一步:准备一个带自定义节点的流程图
<script setup> import { ref } from 'vue' import { VueFlow } from '@vue-flow/core' import CustomNode from './CustomNode.vue' // 节点与边数据 const nodes = ref([ { id: '1', type: 'custom', position: { x: 0, y: 0 }, data: { label: '节点 A' } }, ]) </script> <template> <VueFlow :nodes="nodes" fit-view-on-init> <template #node-custom="nodeProps"> <CustomNode :data="nodeProps.data" :label="nodeProps.label" /> </template> </VueFlow> </template>第二步:在自定义节点内部放置 NodeToolbar
<script lang="ts" setup> import { Handle, Position } from '@vue-flow/core' import { NodeToolbar } from '@vue-flow/node-toolbar' interface NodeData { toolbarVisible: boolean toolbarPosition: Position } interface Props { data: NodeData label: string } defineProps<Props>() </script> <template> <!-- 通过 is-visible 强制显示,position 控制出现方位 --> <NodeToolbar :is-visible="data.toolbarVisible" :position="data.toolbarPosition"> <button>delete</button> <button>copy</button> <button>expand</button> </NodeToolbar> <!-- 节点本体 --> <div :style="{ padding: '10px 20px' }"> {{ label }} </div> <!-- 连接点 --> <Handle type="target" :position="Position.Left" /> <Handle type="source" :position="Position.Right" /> </template>关键点:
- 未显式传入
nodeId时,NodeToolbar 通过 Vue 的依赖注入机制自动获取当前所在节点的 id(详见下文源码分析); - 工具栏内容通过默认插槽任意定制,不限于按钮;
- 节点数据
data中可以携带toolbarVisible、toolbarPosition等字段,实现每个节点各自的工具栏配置。
Props 详解
NodeToolbar 的 Props 定义在 src/types.ts,官方文档(docs/src/guide/components/node-toolbar.md)汇总如下:
| 名称 | 定义 | 类型 | 可选 | 默认值 |
|---|---|---|---|---|
nodeId | 工具栏要挂载到的节点(或节点数组) | string \| string[] | 是 | 上下文中的节点 ID |
isVisible | 强制控制工具栏可见性 | boolean | 是 | 节点被选中 |
position | 工具栏出现方位(top / left / right / bottom) | Position | 是 | Position.Top |
offset | 工具栏与节点的间距 | number | 是 | 10 |
align | 工具栏沿节点边的对齐方式(center / start / end) | 'center' \| 'start' \| 'end' | 是 | 'center' |
nodeId:多节点共享一个工具栏
nodeId支持传入单个字符串或字符串数组,这是把一个工具栏同时服务多个节点的关键能力:
<NodeToolbar :node-id="['node-a', 'node-b']" position="bottom"> <button>批量操作</button> </NodeToolbar>此时工具栏的定位基准是这些节点外接矩形的包围盒(见下方“定位算法”),适合对一组节点做批量操作。
isVisible:两种显示模式
- 不传
isVisible:默认行为是“节点被选中时自动显示工具栏”(仅当恰好选中 1 个节点且该节点就是工具栏所属节点时); - 传入布尔值:完全由你控制显隐,比如结合
data.toolbarVisible做“常驻工具栏”或“悬停显示”。
从源码(NodeToolbar.vue)看,判定逻辑是:
const isActive = computed(() => typeof props.isVisible === 'boolean' ? props.isVisible : nodes.value.length === 1 && nodes.value[0].selected && getSelectedNodes.value.length === 1, )即:只有当你显式传入isVisible时才以你的值为准;否则要求当前选中节点唯一且恰好是工具栏绑定的节点。1.1.1 版本将isVisible的默认值改为undefined(见 CHANGELOG.md),正是为了让“是否显式传入布尔值”这一判断可被可靠区分。
position与offset:方位与间距
position使用核心包导出的Position枚举(定义于 packages/core/src/types/flow.ts):
export enum Position { Left = 'left', Top = 'top', Right = 'right', Bottom = 'bottom', }offset默认10,表示工具栏与节点边缘之间的像素距离。
align:沿节点边的对齐方式(1.1.0 新增)
align是 1.1.0 版本新增的 Prop(见 CHANGELOG.md),控制工具栏沿节点边(top 边或 left/right 边)的对齐位置:
'center'(默认):居中对齐;'start':靠起点对齐(顶部工具栏靠左、底部靠左、左右侧工具栏靠上);'end':靠终点对齐(顶部工具栏靠右、底部靠右、左右侧工具栏靠下)。
该参数在源码中被映射为一个 0~1 的alignmentOffset参与坐标计算(见下文公式)。
Slots
NodeToolbar 只暴露一个默认插槽(docs/src/guide/components/node-toolbar.md):
| 名称 | 定义 |
|---|---|
default | 工具栏内容,任意元素或组件 |
工具栏容器默认带有vue-flow__node-toolbar类名,可通过全局 CSS 定制样式(参考 docs/examples/node-toolbar/App.vue 中的示例样式:flex 布局、背景色、圆角、阴影等)。
源码级原理:工具栏如何“跟随”节点
要真正用好 NodeToolbar,理解其底层实现非常关键。核心源码在 packages/node-toolbar/src/NodeToolbar.vue。
1. 自动绑定当前节点:依赖注入
const contextNodeId = inject(NodeIdInjection, null)当自定义节点在#node-xxx插槽中被渲染时,Vue Flow 核心会向该子树注入当前节点 id。因此在节点模板内部直接写<NodeToolbar>时,无需手动传nodeId;若在节点外部使用,则必须显式传nodeId。
2. 收集目标节点
const nodes = computed(() => { const nodeIds = Array.isArray(props.nodeId) ? props.nodeId : [props.nodeId || contextNodeId || ''] return nodeIds.reduce<GraphNode[]>((acc, id) => { const node = findNode(id) if (node) acc.push(node) return acc }, []) })通过核心包useVueFlow()提供的findNode查找节点对象,支持单节点与多节点。
3. 包围盒计算
工具栏的定位基准是所有目标节点的外接矩形:
const nodeRect = computed(() => getRectOfNodes(nodes.value))getRectOfNodes是核心包工具函数(packages/core/src/utils/graph.ts),它遍历节点,合并每个节点computedPosition(位置)与dimensions(尺寸),求出覆盖所有节点的最小矩形(bounding box)。
4. 分层:zIndex 自动提升
const zIndex = computed(() => Math.max(...nodes.value.map((node) => (node.computedPosition.z || 1) + 1)))工具栏的 z-index 恒为其绑定节点的 z 值 + 1,确保工具栏永远浮于节点之上,即使多个节点重叠也不会被遮挡。
5. 定位公式
function getTransform(nodeRect, transform, position, offset, align): string { let alignmentOffset = 0.5 if (align === 'start') alignmentOffset = 0 else if (align === 'end') alignmentOffset = 1 // ...按 position 计算 pos 与 shift return `translate(${pos[0]}px, ${pos[1]}px) translate(${shift[0]}%, ${shift[1]}%)` }以Position.Top为例:
pos = (nodeRect.x + nodeRect.width * alignmentOffset) * zoom + viewport.x , nodeRect.y * zoom + viewport.y - offset shift = [-100 * alignmentOffset, -100]- 第一部分
translate(px):把工具栏放到节点包围盒的对应边缘,并乘以当前缩放系数zoom并加上视口平移transform.x/y,保证与画布坐标一致; - 第二部分
translate(%):用百分比再做一次平移,实现“以节点边/中心为锚点、以工具栏自身尺寸为基准”的对齐(百分比位移基于元素自身宽度/高度),因此即使工具栏内容大小不同也能正确对齐。
该公式同时处理了Right、Bottom、Left三个方位(NodeToolbar.vue),这正是工具栏能随画布缩放平移而始终贴在节点旁的原因。
6. 渲染:Teleport 到视口容器
<Teleport :to="viewportRef" :disabled="!viewportRef"> <div v-if="isActive && nodes.length" v-bind="$attrs" :style="wrapperStyle" class="vue-flow__node-toolbar"> <slot /> </div> </Teleport>工具栏通过Teleport挂载到核心包的视口 DOM 容器(viewportRef)中,从而与节点一样处于同一坐标变换体系之下;同时只有isActive为真且存在目标节点时才渲染。
7. 兼容性与属性透传
组件以compatConfig: { MODE: 3 }声明,兼容@vue/compat过渡模式(1.0.5 变更,见 CHANGELOG.md),并设置inheritAttrs: false以便通过v-bind="$attrs"把外部属性手动应用到工具栏容器上。
实战示例:完整可运行方案
仓库自带的演示位于 docs/examples/node-toolbar/App.vue,展示了五种典型场景:
| 节点 | 配置 | 效果 |
|---|---|---|
| 节点 1 | toolbarPosition: Position.Top | 工具栏显示在节点上方 |
| 节点 2 | toolbarPosition: Position.Right | 工具栏显示在节点右侧 |
| 节点 3 | toolbarPosition: Position.Bottom | 工具栏显示在节点下方 |
| 节点 4 | toolbarPosition: Position.Left | 工具栏显示在节点左侧 |
| 节点 5 | toolbarVisible: true | 常驻显示,不依赖选中状态 |
对应的节点实现(docs/examples/node-toolbar/ToolbarNode.vue)展示了两个进阶用法:
- 工具栏内操作节点数据:通过
useVueFlow()的updateNodeData更新节点data.action,实现“选中某个表情”这类节点级状态变更:const { updateNodeData } = useVueFlow() // 点击按钮时: updateNodeData(props.id, { action }) - 结合选中态做样式反馈:利用节点自身的
.selected类(示例中给.vue-flow__node-menu.selected加了蓝色描边),配合默认选中时显示工具栏的行为,形成完整的“选中即出现操作栏”交互闭环。
样式定制建议
工具栏容器类名为vue-flow__node-toolbar,官方示例(docs/examples/node-toolbar/App.vue)给出了不错的起点:
.vue-flow__node-toolbar { display: flex; gap: 0.5rem; align-items: center; background-color: #2d3748; padding: 8px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); }也可以直接在 NodeToolbar 上绑定 class / style,因为组件会通过$attrs把它们透传到工具栏容器上。
版本演进速览
根据 packages/node-toolbar/CHANGELOG.md,该包的关键演进如下:
- 1.0.0:新增 node-toolbar 包(#476);
- 1.0.1:改用重命名后的
ViewportTransform类型(#553); - 1.0.2:等待视口 ref 可用后再进行 Teleport,避免渲染时机问题(#569);
- 1.0.3:修正 package.json 的
main字段; - 1.0.4:升级 Vite 4 并更新依赖(#616);
- 1.0.5:增加 compat 模式以兼容
@vue/compat(#682); - 1.0.6:修正 UMD 包名,使用正确的核心包 UMD 名称(#716);
- 1.0.7:在 package.json 中新增
exports字段(#865); - 1.1.0:新增
alignProp(#953); - 1.1.1:
isVisible默认值改为undefined(#1785)。
其中两个变更对使用者影响最大:1.1.0 的align让工具栏对齐更灵活;1.1.1 的isVisible默认值调整修正了“未显式传入时默认跟随选中态”的判断逻辑,升级后建议重新验证自定义节点的工具栏显隐行为。
小结
NodeToolbar 通过依赖注入自动绑定节点、基于包围盒与视口变换计算定位、借助 Teleport 与核心视图保持同步,并以isVisible双模式(强制显示 / 跟随选中)提供灵活的显隐控制。无论是单节点操作、多节点批量工具栏,还是“选中即弹出”的交互设计,它都能与 Vue Flow 核心无缝协作,是扩展节点交互能力的高性价比组件。
- 前端
- UI组件
【免费下载链接】vue-flow
A highly customizable Flowchart component for Vue 3. Features seamless zoom & pan 🔎, additional components like a Minimap 🗺 and utilities to interact with state and graph.
相关推荐
Vue Flow NodeToolbar 节点悬浮工具栏组件使用与源码解析
Vue Flow NodeToolbar 节点悬浮工具栏组件使用与源码解析 本指南围绕 Vue Flow 官方插件 @vue flow/node toolbar
前端UI组件Vue Flow Node Toolbar 组件完全指南:为节点打造浮动工具栏
Vue Flow Node Toolbar 组件完全指南:为节点打造浮动工具栏 NodeToolbar 是 Vue Flow 生态中的官方附加组件(additi
前端UI组件awesome-blender完整指南:10分钟吃透数百个免费Blender插件与纹理资源
awesome blender完整指南:10分钟吃透数百个免费Blender插件与纹理资源 awesome blender是一个持续维护的开源清单项目:把数百个
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考