2026/10/9 1:35:49

OpenPencil 属性面板开发指南:用 composable-first 与 headless 原语构建可绑定的控制面板

OpenPencil 属性面板开发指南:用 composable-first 与 headless 原语构建可绑定的控制面板 前端桌面应用AI 应用MCP 服务【免费下载链接】open-pencilAI-native design editor. Open-source Figma alternative.项目地址https://gitcode.com/gh_mirrors/op/open-pencil点击查看免费下载open-pencil/vue是 OpenPencilAI 原生的开源设计编辑器面向自定义编辑器外壳custom editor shell的 Vue 组件库。属性面板Property Panel是设计工具中最核心的交互界面之一本文将以官方指南为基础深入讲解如何在open-pencil/vue中构建属性面板何时使用 composables 驱动状态与动作、何时使用无强加样式的 headless 原语如PropertyListRoot组织列表结构以及如何通过BindableValueRoot让字段与变量/设计令牌design token建立非破坏性的绑定关系。读完本文你将掌握从零搭建位置/尺寸面板、fills 列表面板和绑定感知字段的完整实战方案。一、构建哲学为什么属性面板是 composable-first在 OpenPencil 的属性面板设计中见 packages/docs/pl/programmable/sdk/guides/property-panels.md官方给出的核心取舍标准非常明确如果面板主要需要从当前选中项计算出的值以及修改这些值的动作——请使用 composable。如果面板的主要难点是复用数组/列表结构增删改、排序、可见性切换等——请选择无强加样式的 headless 组件例如PropertyListRoot。这一原则在 vue/src/index.ts 的导出结构中体现得淋漓尽致控制逻辑类 API如useLayout、useAppearance、useTypography、useFillControls、useStrokeControls、useEffectsControls、useExport全部以 composable 形式导出见第 104–129 行而结构类 API如LayoutControlsRoot、PropertyListRoot则以组件形式导出见第 217、279 行附近。一句话概括这套 API 分层composables 负责数据与行为headless 组件负责布局与协调而具体的外观颜色、间距、字号完全由你的编辑器外壳自定义。这保证了 OpenPencil 官方应用皮肤与第三方编辑器外壳可以共享同一套底层状态机却呈现截然不同的 UI。二、常用控制 composables 总览按照面板内容类型官方把 composables 分为两组标准属性区块usePosition()—— 位置、尺寸、旋转、对齐、翻转useLayout()—— 自动布局Auto Layout相关属性useAppearance()—— 外观属性useTypography()—— 字体排版属性useExport()—— 导出相关属性。列表型属性区块useFillControls()—— 填充fills列表useStrokeControls()—— 描边strokes列表useEffectsControls()—— 效果effects列表。这些 *Controls 后缀的 composable 通常不直接管理列表本身而是为列表提供默认新项与变量绑定辅助能力。以useFillControls为例vue/src/controls/fill/use.ts 的实现非常精简export function useFillControls() { const ctx useColorVariableBinding(fills) return { ...ctx, defaultFill: DEFAULT_SHAPE_FILL } }它内部通过useColorVariableBinding(fills)获得颜色变量绑定能力并暴露defaultFill来自open-pencil/core/constants的DEFAULT_SHAPE_FILL作为新增填充项的默认值。与之配套的列表操作则交给useEditorPropertyList/PropertyListRoot完成——这正是composable 管状态、组件管结构分工的典型样例。三、示例一位置与尺寸面板usePosition先看官方给出的最小可用实现它用usePosition生成 4 个受控输入框script setup langts import { usePosition } from open-pencil/vue const { x, y, width, height, updateProp, commitProp } usePosition() /script template div classgrid grid-cols-2 gap-2 input :valuex inputupdateProp(x, Number(($event.target as HTMLInputElement).value)) / input :valuey inputupdateProp(y, Number(($event.target as HTMLInputElement).value)) / input :valuewidth inputupdateProp(width, Number(($event.target as HTMLInputElement).value)) / input :valueheight inputupdateProp(height, Number(($event.target as HTMLInputElement).value)) / /div /template这里updateProp负责把输入同步到选中节点预览阶段commitProp负责在交互结束时落盘提交阶段。两阶段分离正是设计工具中拖拽/输入时实时预览、结束后可撤销体验的基础。usePosition 的底层实现剖析阅读 vue/src/controls/position/use.ts 可以还原出usePosition的完整能力第 21–111 行读取值返回x、y、width、height、rotation五个响应式计算属性。其中x/y/rotation通过panelPosition/panelRotation来自open-pencil/core/geometry读取会换算成画布上节点边界框在面板中显示的值并对旋转取整第 29–32 行width/height直接读取节点尺寸第 46–47 行。多选混合值panelProp(key)会把所有选中节点在该键上的显示值做对比若不一致则返回MIXED哨兵值第 35–42 行这是面板上显示混合—状态的依据。预览式更新updateProp内部调用usePropScrub的updateEach对x/y使用panelPositionChange、对rotation使用panelRotationChange逐节点换算第 58–68 行保证输入的数字与面板显示值语义一致commitProp负责提交、cancelProp负责取消Esc 回退。辅助动作align(axis, pos)对齐、flip(axis)翻转、rotate(degrees)旋转直接代理到editor.alignNodes/editor.flipNodes/editor.rotateNodes第 78–88 行。从实现可以看出输入的数字不是简单地写入节点属性而是经过几何换算后再写回——这是面板显示值与场景图实际坐标存在差异旋转、父级变换时保证所见即所得的关键。四、示例二fills 列表面板PropertyListRoot当属性本身是一组无序但有序的数组项如 fills、strokes、effects时官方推荐用PropertyListRoot这类 headless 列表原语。官方示例script setup langts import { PropertyListRoot, useEditorPropertyList, useFillControls } from open-pencil/vue const fillControls useFillControls() const fills useEditorPropertyList(fills) /script template PropertyListRoot prop-keyfills :itemsfills.items.value :mixedfills.isMixed.value addfills.actions.add removefills.actions.remove v-slot{ items, actions } div v-for(fill, index) in items :keyindex {{ fill.type }} button clickactions.remove(index)Usuń/button /div button clickactions.add(fillControls.defaultFill)Dodaj zalew/button /PropertyListRoot /template上面的按钮文案 Usuń 与 Dodaj zalew 是波兰语版指南原文意为删除与添加填充在正式产品中应接入你自己的 i18n 文案。数据源useEditorPropertyList 如何工作useEditorPropertyList导出于 vue/src/index.ts 第 279 行是列表面板的状态枢纽它做了四件事读取数组通过useNodeProps()拿到选中节点与活动节点items计算属性返回活动节点的node[propKey]数组第 32–35 行当多选且值不一致时isMixed为真并返回空数组第 31–33 行。多目标批量add/remove/reorder在多选时会遍历所有选中节点targetNodes()并把整个操作包进editor.undo.runBatch(label, apply)保证一次撤销还原全部节点第 50–80、131–142 行。交互合并批update/patch修改单个条目使用useUndoBatch的batch.ensure(key, label)把连续的中间状态合并进同一个撤销条目第 82–110 行——这正是拖拽滑块连续改变数值时撤销仍表现为一次操作的原理。完整动作集返回actions.add / remove / update / patch / toggleVisibility / reorder第 144–151 行与PropertyListRoot支持的事件一一对应。结构层PropertyListRoot 的 headless 设计阅读 vue/src/primitives/PropertyList/PropertyListRoot.vue 可以看到它的极简骨架它不渲染任何可见 DOM只把items、isMixed、disabled、keyOf和actions通过默认插槽暴露给子内容第 66–72 行并通过providePropertyList注入上下文第 62 行。它声明了完整的事件集add、remove、update、patch、toggleVisibility、reorder第 23–30 行每个动作在disabled时会被静默忽略第 41–60 行。同一目录还提供了配套的无样式子组件 PropertyListItem.vue、PropertyListAdd.vue、PropertyListRemove.vue、PropertyListVisibility.vue可组合出增删、显隐、排序等常见行结构。子组件想读取上下文时可用usePropertyList()composableAPI 文档见 use-property-list它返回最近一层PropertyListRoot的 items、mixed 状态与全部 actions适合封装独立行组件。五、绑定感知字段BindableValueRoot 的使用规范当字段的值可以绑定到一个变量或外部设计令牌时官方要求把字段包进BindableValueRootheadless 原语导出于 vue/src/index.ts 第 345 行附近。这一节是属性面板与 OpenPencil 变量系统variables衔接的关键官方给出了五条明确规范空闲时展示变量身份字段未被编辑时应显示变量名OpenPencil 应用皮肤用紫色药丸样式展示变量名解析后的计算值可以放在 tooltip 等辅助 UI 中聚焦/打开选择器不能破坏绑定获取焦点或打开变量选择器绝不允许顺带解除绑定按需应用编辑策略detach-on-edit编辑即解除绑定、readonly-when-bound绑定时只读、edit-variable编辑变量本身这三种策略只应在用户实际修改值时生效显式解除绑定放在选择器里独立的解除绑定操作应放在变量选择器内部而不是做成字段旁边容易被误触的一键图标绑定操作要走提供者批量事务绑定替换、编辑时解除绑定、多对象变更必须在同一次 provider 批量batch中完成保证撤销/重做一致性。OpenPencil 官方应用皮肤的具体呈现是字段空闲时显示紫色变量名药丸NumberField进入编辑态时显示解析后的数值。你的自定义外壳完全可以换一种呈现方式因为BindableValueRoot本身不携带任何样式。源码视角BindableValueRoot 的状态机与策略阅读 vue/src/primitives/BindableValue/BindableValueRoot.vue 可以验证上述规范在实现层的落地状态机state有unbound未绑定、bound已绑定、mixed混合、unresolved未解析四种第 56–59 行并通过stateAttrs以data-unbound/data-bound/data-mixed/data-picker-open/data-policy等 data 属性暴露给外层第 74–81 行方便你用纯 CSS 实现外观差异。非破坏性聚焦beginMutation只有在真正开始改值beginMutation被调用时才执行策略动作聚焦与打开选择器openPicker只改变open状态不触碰绑定第 114–116 行。策略执行beginMutation依据policy分支处理——readonly-when-bound直接拒绝返回falsedetach-on-edit在已绑定/混合态下先provider.unbind并快照绑定第 145–169 行edit-variable则通过prepareBindingEdits准备对变量本身的编辑第 152–156 行cancelMutation会通过 provider 批量回滚或按快照恢复绑定第 200–205 行。事务保证若 provider 实现了beginBatch/commitBatch/rollbackBatch则一次完整的绑定替换/编辑-提交交互被包进同一批事务第 43–49、160、186–189 行这正是规范第 5 条要求的单次 provider 批量。对变量绑定的 provider 实现可进一步参考 vue/src/controls/binding-provider/ 目录含prepare-edits.ts、types.ts与 context以及颜色变量绑定专项的 use-color-variable-binding.md。六、API 选择经验法则最后官方给出的 API 选择规则可以浓缩为一句话直接的控制逻辑用 composables状态 动作当难点在于反复出现的列表、树、插槽的协调时用无样式的结构原语structural primitives。按此原则拆解到具体场景面板需求首选方案单个数值属性x/y/宽高/旋转/对齐/翻转usePosition自动布局/外观/排版/导出区块useLayout/useAppearance/useTypography/useExportfills/strokes/effects 列表 默认新项useFillControls/useStrokeControls/useEffectsControls提供默认值与绑定能力列表的增删改/排序/显隐/混合态useEditorPropertyListPropertyListRoot可绑定到变量/令牌的字段BindableValueRoot包裹配合 provider 批量事务这样组合出来的面板既拥有与官方应用一致的底层数据语义混合值、预览式更新、撤销批又能 100% 自定义外观是 OpenPencil 自定义编辑器外壳见 custom-editor-shell推荐的标准做法。七、相关 API 索引usePosition —— x/y/宽高/旋转/对齐/翻转与数值属性预览-提交useLayout —— 自动布局面板useAppearance —— 外观面板useTypography —— 排版面板useFillControls —— fills 默认值defaultFilluseStrokeControls —— strokes 默认值useEffectsControls —— effects 默认值PropertyListRoot —— headless 列表根组件usePropertyList —— 子组件读取列表上下文的 composable以上 API 的 TypeScript 实现全部位于 packages/vue/src 的controls/状态层与primitives/无样式组件层官方应用的属性面板即由这些构件组合而成可作为你的自定义实现最直接的参照。赞分享前端桌面应用AI 应用MCP 服务【免费下载链接】open-pencilAI-native design editor. Open-source Figma alternative.项目地址https://gitcode.com/gh_mirrors/op/open-pencil点击查看免费下载相关推荐AppearanceControlsRoot 深度解析用 Headless 原语构建 OpenPencil 外观属性面板AppearanceControlsRoot 深度解析用 Headless 原语构建 OpenPencil 外观属性面板 AppearanceControls前端桌面应用AI 应用MCP 服务OpenPencil 描边属性面板开发指南深入 useStrokeControls ComposableOpenPencil 描边属性面板开发指南深入 useStrokeControls Composable useStrokeControls 是 OpenPe前端桌面应用AI 应用MCP 服务OpenPencil 属性面板开发指南用 open-pencil/vue 组合式 API 与无头列表原语构建属性面板OpenPencil 属性面板开发指南用 open pencil/vue 组合式 API 与无头列表原语构建属性面板 OpenPencil 是开源的 AI前端桌面应用AI 应用MCP 服务上一篇为什么选择whatlanggoGo语言无依赖自然语言检测库深度测评下一篇boto v2.34.0 版本解析eu-central-1 区域支持、IAM 虚拟 MFA 设备与 SigV4 修复实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考