- 前端
- 桌面应用
- AI 应用
- MCP 服务
【免费下载链接】open-pencil
AI-native design editor. Open-source Figma alternative.
useSelectionCapabilities()是@open-pencil/vueSDK 提供的选择驱动能力查询组合式函数,它基于当前场景选择状态,暴露一组响应式布尔值,用于判断"删除、复制、创建组件、移动到页面、跳转主组件、缩放至选区"等常见编辑器操作当前是否可用。本文以 packages/docs/programmable/sdk/api/composables/use-selection-capabilities.md 为骨架,结合 packages/vue/src/editor/selection-capabilities/use.ts 的完整实现、命令定义 与 组合式函数索引 的上下文,讲解如何在菜单、工具栏、快捷键、操作按钮与上下文面板中正确使用它,并剖析其底层原理与全部能力位。
一、它解决什么问题
在设计编辑器类应用中,大量 UI 元素需要"根据当前选中的对象,决定某个操作是否可执行"。例如:
- 没有任何选中对象时,
删除、复制按钮应当置灰; - 选中了 2 个及以上节点时,
编组才可用; - 选中实例(INSTANCE)时,
跳转到主组件才有意义; - 只有选中组件(COMPONENT)时,
创建实例才允许执行。
如果在每个组件里都手动读取场景图(scene graph)再逐条判断,代码会重复、分散且容易漏判。useSelectionCapabilities正是为此设计的:它把"选择状态 → 操作是否可用"的派生逻辑集中收敛,向 UI 层暴露命令友好的布尔值。
官方文档给出的典型用途覆盖:
- 菜单(menus)
- 工具栏(toolbars)
- 键盘快捷键(keyboard shortcuts)
- 操作按钮(action buttons)
- 上下文面板(contextual panels)
它位于 SDK 的 "Selection and commands" 能力族中,与 useSelectionState 和 useEditorCommands 一起,构成了选择驱动 UI 的完整工具箱。
二、基本用法与返回值
2.1 导入与解构
从包入口导入并调用即可:
import { useSelectionCapabilities } from '@open-pencil/vue' const caps = useSelectionCapabilities()SDK 在 packages/vue/src/index.ts 中公开导出该组合式函数,底层实现位于 packages/vue/src/editor/selection-capabilities/use.ts。
2.2 文档示例:一个最小操作栏
官方文档提供了一个可直接运行的 Vue 单文件组件示例,三个按钮分别受canDuplicate、canDelete、canCreateComponent控制:
<script setup lang="ts"> import { useSelectionCapabilities } from '@open-pencil/vue' const { canDelete, canDuplicate, canCreateComponent } = useSelectionCapabilities() </script> <template> <div class="flex gap-2"> <button :disabled="!canDuplicate">Duplicate</button> <button :disabled="!canDelete">Delete</button> <button :disabled="!canCreateComponent">Make component</button> </div> </template>在 Vue 模板中,ref/computed会被自动解包,因此:disabled="!canDelete"直接读取计算值即可,无需.value。
三、完整能力位速查表
虽然文档正文只显式列出 6 个布尔值,但源码实现(packages/vue/src/editor/selection-capabilities/use.ts)实际暴露了 30 余个能力位。下表整理了每个能力位的语义与判定依据,可直接作为开发参考:
| 能力位 | 可用条件(源码依据) | 典型用途 |
|---|---|---|
canCopy | 有选中对象(hasSelection) | 复制菜单项 |
canCut | 有选中对象 | 剪切菜单项 |
canPaste | 恒为true | 粘贴菜单项 |
canDelete | 有选中对象 | 删除按钮 |
canDuplicate | 有选中对象 | 复制/原位复制 |
canExportSelection | 有选中对象 | 导出菜单 |
canGroup | selectedCount >= 2 | 编组命令 |
canFrameSelection | 有选中对象 | 用 Frame 包裹选区 |
canUngroup | 选中节点类型为GROUP | 取消编组 |
canCreateComponent | 有选中对象 | 创建组件 |
canCreateComponentSet | 选中项 ≥ 2 且全部为COMPONENT | 创建组件集 |
canDetachInstance | 选中节点为INSTANCE | 分离实例 |
canWrapInAutoLayout | 有选中对象 | 包裹为自动布局 |
canToggleMask | 有选中对象 | 切换蒙版 |
canBringToFront | 有选中对象 | 置顶 |
canSendToBack | 有选中对象 | 置底 |
canToggleVisibility | 有选中对象 | 显示/隐藏 |
canToggleLock | 有选中对象 | 锁定/解锁 |
canFlip | 有选中对象 | 水平/垂直翻转 |
canDistribute | editor.canDistributeNodes(选中节点)为真 | 分布对齐 |
canBooleanOperation | 选中 ≥ 2 且全部可参与布尔运算 | 布尔并/减/交/排除 |
canFlatten | 选中节点均可转换为布尔源节点 | 合并为单一形状 |
canOutlineText | 选中全部为TEXT且可转换 | 文本转路径 |
canOutlineStroke | 选中全部含可见描边且可转换 | 描边转路径 |
canGoToMainComponent | 选中节点为INSTANCE | 跳转主组件 |
canCreateInstance | 选中节点类型为COMPONENT | 创建实例 |
canMoveToPage | 有选中对象且页面数 > 1 | 移动到其他页面 |
canSetOpacity | 有选中对象 | 设置不透明度 |
canSelectAll | 当前页面有子节点 | 全选/反选 |
canUndo | 矢量编辑态存在,或撤销栈可用 | 撤销 |
canRedo | 矢量编辑态存在,或重做栈可用 | 重做 |
canZoomToSelection | 有选中对象 | 缩放至选区 |
关键判定逻辑解读
- 基于选择的位:
canCopy、canCut、canDelete、canDuplicate等一律由hasSelection派生,见 packages/vue/src/editor/selection-state/use.ts,而hasSelection是selectedIds.size > 0。 - 基于类型的位:
canUngroup依赖isGroup,canDetachInstance/canGoToMainComponent依赖isInstance,canCreateInstance检查selectedNode.value?.type === 'COMPONENT',这些类型判定同样来自useSelectionState。 - 基于场景图的位:
canDistribute、canBooleanOperation、canFlatten、canOutlineText、canOutlineStroke、canMoveToPage、canSelectAll使用useSceneComputed在场景图层计算,例如canMoveToPage要求editor.graph.getPages().length > 1,canSelectAll要求当前页存在子节点。 - 基于历史的位:
canUndo/canRedo订阅history:changed事件并读取editor.undo,且矢量编辑态(nodeEditState)下保持启用,以保证快捷键能到达会话级历史(源码注释明确说明此设计,见 packages/vue/src/editor/selection-capabilities/use.ts)。 - 恒真位:
canPaste恒为true,原因是剪贴板状态与选区无关,粘贴可用性由剪贴板内容在命令执行时另行判断。
四、实战场景:菜单、快捷键与上下文面板
4.1 用能力位门控菜单项
菜单条目按能力位启用/禁用,与命令模型天然契合:
const { canMoveToPage, canGoToMainComponent } = useSelectionCapabilities()例如"移动到页面"条目仅在canMoveToPage为真时显示或可点击(要求有选中对象且存在第二个页面),"跳转到主组件"仅在选中实例时可用。
4.2 只在有用时启用缩放命令
"缩放至选区"(Zoom to selection)在无选中对象时没有意义,直接由canZoomToSelection门控:
const { canZoomToSelection } = useSelectionCapabilities()4.3 在编辑器命令模型中的角色
能力位不只是给按钮用的,它们直接喂给命令系统。在 packages/vue/src/editor/commands/use.ts 中,useEditorCommands()内部同时调用useSelectionState()与useSelectionCapabilities(),将能力位注入createEditorCommandMap:
const capabilities = useSelectionCapabilities() const commands = createEditorCommandMap({ editor, selection, capabilities, messages: t, otherPages, moveSelectionToPage, getOpacityTarget: () => opacityTarget })随后在 packages/vue/src/editor/commands/selection.ts 中,每个选择类命令都用对应能力位作为enabled判定:
'selection.duplicate': { id: 'selection.duplicate', get label() { return t.value.duplicate }, enabled: capabilities.canDuplicate, run: () => editor.duplicateSelected() }, 'selection.delete': { id: 'selection.delete', get label() { return t.value.delete }, enabled: capabilities.canDelete, run: () => editor.deleteSelected() }, 'selection.createComponent': { id: 'selection.createComponent', get label() { return t.value.createComponent }, enabled: capabilities.canCreateComponent, run: () => editor.createComponentFromSelection() }命令定义由createEditorCommandMap汇总自edit、selection、view三组(packages/vue/src/editor/commands/definitions.ts),能力位因此统一驱动了菜单模型、快捷键与命令面板的可用状态——这也是文档推荐"用命令而非裸调用"构建 UI 的原因。
4.4 与相关组合式函数的协作
- useSelectionState:提供原始选择状态(
selectedIds、selectedNode、hasSelection、isInstance、isGroup等),是能力位的输入基础; - useEditorCommands:在能力位之上构建命令级接口,供菜单/工具栏/快捷键直接调用。
三者构成"原始状态 → 能力位 → 命令执行"的完整链路。
五、实现原理:从选择状态到能力位
5.1 数据来源
useSelectionCapabilities()内部首先获取选择状态:
const selection = useSelectionState() const { editor, selectedIds, selectedNode, selectedCount, hasSelection } = selectionuseSelectionState()的实现(packages/vue/src/editor/selection-state/use.ts)基于useEditor()获取编辑器实例,并通过useSceneComputed订阅场景图变化:
const selectedIds = useSceneComputed(() => editor.state.selectedIds) const hasSelection = computed(() => selectedIds.value.size > 0)因此只要选区变化,所有依赖它的能力位都会自动重算并触发 UI 更新,无需手动刷新。
5.2 响应式与撤销历史的联动
撤销/重做能力位需要感知历史状态变化,源码通过shallowRef与编辑器事件实现:
const history = shallowRef(editor.undo) useEditorEvent('history:changed', () => triggerRef(history)) canUndo: useSceneComputed(() => editor.state.nodeEditState != null || history.value.canUndo), canRedo: useSceneComputed(() => editor.state.nodeEditState != null || history.value.canRedo)useEditorEvent由 SDK 公开导出(packages/vue/src/index.ts),history:changed事件触发后通过triggerRef强制刷新引用,从而联动更新canUndo/canRedo。
5.3 场景图级能力位
canBooleanOperation、canFlatten、canOutlineText、canOutlineStroke这类需要逐节点检查的位,统一基于canMakeBooleanSourceNode判定——即节点能否作为布尔运算的源。例如canOutlineStroke还额外要求节点含可见描边:
canOutlineStroke: useSceneComputed(() => { const nodes = editor.getSelectedNodes() return ( nodes.length > 0 && nodes.every( (node) => hasVisibleStrokeSourceNode(node, editor.graph) && canMakeBooleanSourceNode(node, editor.graph) ) ) })canDistribute则直接调用编辑器能力判定:
canDistribute: useSceneComputed(() => editor.canDistributeNodes([...editor.state.selectedIds]))这些实现展示了能力位的通用设计模式:简单位走选区派生,复杂位走场景图查询,统一以computed/useSceneComputed暴露为响应式布尔值。
六、配套资源与延伸阅读
- 组合式函数总览:Composables 索引
- 原始选择状态:useSelectionState
- 命令级接口:useEditorCommands
- 命令定义(能力位的消费方):packages/vue/src/editor/commands/selection.ts
- 菜单模型:useMenuModel
- Vue SDK 架构说明:packages/vue/ARCHITECTURE.md 与 packages/vue/README.md
七、使用要点小结
- 选择后即用:
useSelectionCapabilities()必须在提供编辑器上下文的子树内调用(其内部依赖useEditor()/useSelectionState()); - 解构即用:返回的每个布尔值都是响应式的,直接绑定
:disabled、v-if或命令的enabled即可; - 优先走命令层:菜单、工具栏、快捷键尽量复用
useEditorCommands的命令体系,能力位已自动接入命令的enabled判定; - 无需手动同步:选区、场景图、撤销历史变化会自动触发能力位重算,UI 始终保持一致。
- 前端
- 桌面应用
- AI 应用
- MCP 服务
【免费下载链接】open-pencil
AI-native design editor. Open-source Figma alternative.
相关推荐
open-pencil useEditorCommands 详解:用命令层驱动菜单、工具栏与快捷键交互
open pencil useEditorCommands 详解:用命令层驱动菜单、工具栏与快捷键交互 本文围绕 open pencil(AI native 设
前端桌面应用AI 应用MCP 服务open-pencil @open-pencil/vue 中的 ToolbarRoot:为设计编辑器构建 Headless 工具栏原语
open pencil @open pencil/vue 中的 ToolbarRoot:为设计编辑器构建 Headless 工具栏原语 ToolbarRoot
前端桌面应用AI 应用MCP 服务NodeGui QAction 完全指南:用 Node.js 与 CSS 构建跨平台桌面应用中的菜单、工具栏与快捷键动作
NodeGui QAction 完全指南:用 Node.js 与 CSS 构建跨平台桌面应用中的菜单、工具栏与快捷键动作 QAction 是 NodeGui 中
桌面应用跨平台
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考