Appearance
ADR-008: 使用 @vue-flow/node-toolbar 实现节点悬浮面板
Status
Accepted
Date
2026-03-27
Context
NodeShell 双模式需要在节点选中时显示悬浮面板(上方 Toolbar、下方 Prompt + ActionBar)。面板需要:
- 跟随节点位置,在画布缩放/平移时保持相对位置
- 渲染在节点 DOM 之外,不影响节点卡片高度
- 支持
isVisible控制显示/隐藏
Options
A. CSS absolute 定位
在节点卡片内使用 position: absolute; bottom: 100% / top: 100% 将面板定位在节点上方/下方。
- 优点:零依赖,实现简单
- 缺点:面板在节点 DOM 内部,可能被
overflow: hidden裁切;需要手动处理缩放变换下的偏移计算
B. Vue Teleport
用 <Teleport> 将面板渲染到画布 pane 层,手动计算位置。
- 优点:不受节点 DOM 限制
- 缺点:需要手动订阅节点位置变化和画布 viewport 变换,代码复杂度高
C. @vue-flow/node-toolbar(选择此方案)
Vue Flow 官方插件,提供 <NodeToolbar> 组件,内部自动处理位置计算和 viewport 变换。
- 优点:官方维护,自动跟随缩放/平移,API 简洁(
position、offset、isVisible) - 缺点:新增一个依赖包(~5KB gzipped),不提供 CSS(纯 JS 组件)
Decision
选择方案 C。理由:
- 项目已依赖
@vue-flow/core、@vue-flow/background、@vue-flow/minimap,node-toolbar 是同一生态的官方插件 - 自动处理 viewport 变换是核心需求,手写成本高且易出 bug
- 包体积极小,无 CSS 产物
Consequences
- 根目录
package.json新增@vue-flow/node-toolbar依赖 - NodeShell 使用两个
<NodeToolbar>实例(Position.Top和Position.Bottom) - NodeToolbar 可见性通过
v-if条件渲染控制(而非:is-visibleprop 绑定 computed),挂载时始终传:is-visible="true"。这样未选中时 NodeToolbar 不在 DOM 中,避免了不必要的 viewport 订阅开销 - 测试中需要 mock
@vue-flow/node-toolbar模块(vi.mock),因为它依赖 Vue Flow inject - 入场动画使用 opacity-only 的
panel-fade-inkeyframe(fill-mode: both),NodeToolbar 不提供内置 transition 支持