news 2026/9/26 10:05:35

Open-Pencil 中 useSelectionCapabilities:用响应式能力位构建菜单、工具栏与快捷键

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Open-Pencil 中 useSelectionCapabilities:用响应式能力位构建菜单、工具栏与快捷键
  • 前端
  • 桌面应用
  • AI 应用
  • MCP 服务

【免费下载链接】open-pencil

AI-native design editor. Open-source Figma alternative.

项目地址:https://gitcode.com/gh_mirrors/op/open-pencil
点击查看免费下载

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有选中对象导出菜单
canGroupselectedCount >= 2编组命令
canFrameSelection有选中对象用 Frame 包裹选区
canUngroup选中节点类型为GROUP取消编组
canCreateComponent有选中对象创建组件
canCreateComponentSet选中项 ≥ 2 且全部为COMPONENT创建组件集
canDetachInstance选中节点为INSTANCE分离实例
canWrapInAutoLayout有选中对象包裹为自动布局
canToggleMask有选中对象切换蒙版
canBringToFront有选中对象置顶
canSendToBack有选中对象置底
canToggleVisibility有选中对象显示/隐藏
canToggleLock有选中对象锁定/解锁
canFlip有选中对象水平/垂直翻转
canDistributeeditor.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 } = selection

useSelectionState()的实现(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

七、使用要点小结

  1. 选择后即用:useSelectionCapabilities()必须在提供编辑器上下文的子树内调用(其内部依赖useEditor()/useSelectionState());
  2. 解构即用:返回的每个布尔值都是响应式的,直接绑定:disabled、v-if或命令的enabled即可;
  3. 优先走命令层:菜单、工具栏、快捷键尽量复用useEditorCommands的命令体系,能力位已自动接入命令的enabled判定;
  4. 无需手动同步:选区、场景图、撤销历史变化会自动触发能力位重算,UI 始终保持一致。
  • 前端
  • 桌面应用
  • AI 应用
  • MCP 服务

【免费下载链接】open-pencil

AI-native design editor. Open-source Figma alternative.

项目地址:https://gitcode.com/gh_mirrors/op/open-pencil
点击查看免费下载

相关推荐

上一篇:一张消费级4090跑Qwen3-235B-A22B-Thinking-2507?这份极限“抠门”的量化与显存优化指南请收好
下一篇:突破2350亿参数模型的实时交互瓶颈:Qwen3-235B-A22B-Thinking-2507-FP8的KV缓存与PagedAttention优化实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 10:02:47

使用数据规整进行数据离散变量处理

在现代数据分析中,数据规整是一项至关重要的技能。无论是从事数据科学、机器学习,还是在商业分析中进行数据的处理和分析,都离不开数据的预处理与特征工程。尤其是在面对数据中的离散变量时,合理地处理和转换这些变量可以提升模型的预测能力,也能帮助更好地理解数据背后的…

作者头像 李华
网站建设 2026/9/26 10:02:00

AWD作战管理台实战:集中信息与自动化攻防的完整落地指南

1. 项目缘起&#xff1a;为什么我需要一个AWD作战管理台先说结论&#xff1a;AWD&#xff08;Attack With Defense&#xff0c;攻防兼备&#xff09;比赛不是一个人能撑起来的游戏&#xff0c;但很多队伍实际打起来&#xff0c;却常常变成“一个人扛三路”的局面。我在打CTF的第…

作者头像 李华