前端桌面应用AI 应用MCP 服务【免费下载链接】open-pencilAI-native design editor. Open-source Figma alternative.项目地址https://gitcode.com/gh_mirrors/op/open-pencil点击查看免费下载open-pencil/vue的属性面板Property Panels是设计工具中最复杂的 UI 区域之一它既要实时反映当前选区的计算结果又要安全地写回场景图还要支持变量绑定与多对象同步编辑。本篇指南以open-pencil/vue官方文档为核心围绕“composable 优先、无头原语辅助”的架构哲学讲解如何用usePosition、useFillControls等 composable 构建面板状态用PropertyListRoot这类无外观headless原语组织可复用的列表结构并深入BindableValueRoot的绑定语义最终让你能独立搭建一套专业、可维护且尊重设计数据的属性面板。一、面板架构哲学Composable 优先原语补位open-pencil/vue的属性面板设计有两个明确分工见 property-panels.md面板主要需要“选区计算值 修改动作”时优先使用 composable。因为面板的核心工作是把x、opacity、fills这类选中节点的属性投影成响应式状态再把用户的输入写回节点——这正是 composable 的职责。面板需要可复用的数组/列表结构时使用无头原语headless primitive例如PropertyListRoot。当难点在于协调重复的列表、树或插槽结构时由原语负责结构编排外观完全交给调用方。这一原则在 packages/vue/src/index.ts 的导出结构中可以得到印证controls/目录集中存放usePosition、useLayout等控制 composableprimitives/目录则存放PropertyList、BindableValue等无头组件。二、常用控制 Composables标准属性区块的起点2.1 单值属性区块文档列出的五个标准 composable 对应面板中最常见的五个分区Composable用途源码位置usePosition()位置与尺寸x/y、宽高、旋转、对齐、翻转controls/position/use.tsuseLayout()自动布局方向、间距、内边距、网格轨道、尺寸策略controls/layout/use.tsuseAppearance()可见性、不透明度、圆角半径controls/appearance/use.tsuseTypography()文本排版字体族、字重、字号等格式化控制controls/typography/use.tsuseExport()导出相关属性controls/下的导出控制以 usePosition 为例源码显示它基于useNodeProps()获取当前选区的nodes、node、active、isMulti状态然后派生出一组计算属性x、y、width、height直接映射到选中活动节点无节点时回退为0rotation对旋转角做了Math.round取整适合直接渲染进数字输入框动作层updateProp(key, value)即时更新、commitProp(key, value, previous)提交到撤销栈、cancelProp(key)取消预览多选能力align(axis, pos)调用editor.alignNodesflip(axis)调用editor.flipNodesrotate(degrees)调用editor.rotateNodes全部基于ids选中节点 id 列表批量执行。也就是说usePosition不只是返回四个数字它把“单选编辑、多选对齐/翻转/旋转、撤销提交”整套交互都封装好了。类似的useLayout 内部由createLayoutSelectionState、createPaddingActions、createLayoutActions、createGridTrackActions几个工厂函数组合而成覆盖自动布局方向、统一/对称/独立内边距、网格轨道增删等能力useAppearance 则通过createAppearanceStatecreateAppearanceActions提供可见性与圆角编辑并带有expandedCornerNodeId状态用于展开独立圆角输入。2.2 列表型属性区块对于填充fills、描边strokes、效果effects这类“一组对象”的属性文档推荐三个 composableuseFillControls()useStrokeControls()useEffectsControls()以 useFillControls 为例源码极其简洁但信息量很大它继承useColorVariableBinding(fills)的全部行为再额外暴露一个defaultFill——即DEFAULT_SHAPE_FILL来自open-pencil/core/constants。这个默认值正是“添加填充”按钮要用到的素材用户在面板里点“Add fill”得到的就是一个符合 SDK 约定的默认填充对象而不是调用方临时拼出来的结构。三、示例实战一位置与尺寸面板文档给出的位置面板示例完整复刻如下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 中两者都来自usePropScrub(editor)。updateProp是即时写入选区节点适合input拖拽/连续输入时使用commitProp则把“新值 旧值”一起提交给撤销系统适合输入结束、失焦、change时调用。正确的做法是拖动过程中持续updateProp松手/失焦时commitProp这样用户按Ctrl/CmdZ能整段回退。数字安全。示例里用Number(...)把输入框字符串转成数值。updateProp的key类型是NumericNodeProperty来自open-pencil/scene-graph只接受数字所以在绑定到input事件时必须自己做转换与过滤。多选行为。当isMulti为真时updateProp/commitProp作用于nodes.value全部节点——这就是多对象同步编辑的实现路径。若选中多个尺寸不同的节点width/height等计算属性取值自“活动节点”node.value面板需要结合prop属性合并状态自行呈现“mixed混合”提示。四、示例实战二填充列表面板文档给出的填充面板示例是“composable 无头原语”协同的完整范本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)Supprimer/button /div button clickactions.add(fillControls.defaultFill)Ajouter un remplissage/button /PropertyListRoot /template示例按钮文案按法语原文保留为 “Supprimer / Ajouter un remplissage”英文版对应 “Remove / Add fill”。这里有三层值得展开useEditorPropertyList(fills)是列表数据的来源。查看 controls/property-list/use.ts 的源码它返回items当前活动节点的fills数组、isMixed多选时数组属性是否混合、isMulti、active以及一整套actionsadd(item)单对象时向节点数组追加深拷贝structuredClone防共享引用多对象时通过editor.undo.runBatch(label, apply)把对每个节点的写入包进一个批量撤销操作remove(index)过滤掉指定下标多对象同样走批量update(index, item)/patch(index, changes)通过useUndoBatch的batch.ensure合并连续编辑patch只合并部分字段变化toggleVisibility(index)切换单项visible且每次读取editor.getNode(node.id)获取最新节点避免闭包里的过期引用reorder(fromIndex, toIndex)用moveItem在数组内移动元素。也就是说你在模板里拿到的fills.actions.add/remove底层已经在处理“多选批量写入 撤销分组 引用隔离”这些脏活。PropertyListRoot是纯结构协调者。查看 PropertyListRoot.vue它只负责接收prop-key、items、mixed、disabled把add/remove/update/patch/toggleVisibility/reorder六个事件转发成 slot 里的actions对象并通过providePropertyList提供给子组件PropertyListItem、PropertyListAdd、PropertyListRemove、PropertyListVisibility等配套原语共享同一上下文见 primitives/PropertyList。它不渲染任何样式连默认的disabled保护也只在actions里拦截事件转发。useFillControls().defaultFill是“添加”按钮的素材。没有它你得自己拼一个合法的 fill 对象有了它actions.add(fillControls.defaultFill)一行就完成了。五、变量绑定字段BindableValueRoot 的语义与最佳实践当面板字段可以引用变量variable或外部设计令牌design token时文档要求用BindableValueRoot包住该字段。它在 primitives/BindableValue 下实现BindableValueRoot.vue的源码展示了完整的“绑定感知”状态机BindableValueRoot.vue它解析providerproviderProp或注入的provideBindingProvider缺少时直接抛错保证误用能在开发期暴露state通过provider.getState(targets)计算取值包括unbound、bound、unresolved、mixed并渲染成data-unbound、data-bound、data-unresolved、data-mixed、data-picker-open、data-policy等属性stateAttrs让外部样式可以纯靠 CSS 属性选择器区分状态policy默认值为detach-on-edit其余可选值包括readonly-when-bound、edit-variable见BindableValueRootProps定义。文档同时给出了五条绑定交互的硬性规范这是构建“尊重用户数据”的面板必须遵守的空闲时显示变量身份解析值放在辅助 UI字段非编辑态应显示变量名OpenPencil 应用皮肤里是紫色的变量名胶囊解析出的计算值通过 tooltip 等支持性 UI 暴露聚焦或打开变量选择器绝不能破坏绑定把焦点移入字段不等于用户要编辑因此“聚焦即分离”是禁止的只在真正发生修改时才应用detach-on-edit/readonly-when-bound/edit-variable这三种策略都绑定在“用户实际改动值”这一事件上而不是“字段获得焦点”上显式的解除绑定动作放在选择器内部而不是放在字段旁边一个容易误触的一次性图标按钮上把“替换绑定、编辑时分离、多对象更新”放进同一次 provider 批量操作源码里beginProviderBatch/commitProviderBatch/rollbackProviderBatch的交互批处理supportsInteractionBatch正是为此设计——一次交互要么整体生效要么整体回滚配合batchLabel默认Edit bound value进入撤销栈。关于第 1 条的“紫色胶囊”文档特别注明这是 OpenPencil 应用皮肤的实现选择字段空闲时显示紫色变量名NumberField进入编辑模式时才揭示解析后的数字值。BindableValueRoot本身是无外观的自定义编辑器外壳可以完全用不同的方式呈现同一套 headless 状态。六、如何选择 API一句经验法则文档最后给出了一条可操作的判断标准需要直接控制逻辑状态 动作→ 用 composable。典型场景位置、尺寸、透明度、圆角、排版、导出等标准分区直接用usePosition、useAppearance、useTypography等难点在重复的列表/树/插槽协调 → 用结构原语。典型场景填充、描边、效果这类可增删、可排序、可见性可切换的数组属性用PropertyListRoot配合useEditorPropertyList两者不是互斥的填充面板示例就是“composableuseFillControls、useEditorPropertyList提供数据与动作原语PropertyListRoot负责结构”的组合用法。实践中一个复杂面板通常是若干 composable 加上若干原语的混合体。七、相关 API 速查围绕本文主题open-pencil/vue还提供以下 API 供深入阅读usePositionuseLayoutuseAppearanceuseTypographyuseFillControlsuseStrokeControlsuseEffectsControlsPropertyListRoot如需了解这些 composable 与编辑器实例的关系如useEditor、useNodeProps、useUndoBatch可进一步阅读 SDK 架构文档 与 入门指南。结语OpenPencil 的属性面板 API 把“设计工具的脏活”封装成了清晰的层次composable 承载选区状态与写入动作无头原语承载列表/绑定结构BindableValueRoot则用一套严谨的交互规范保护变量绑定不被误伤。掌握“先看状态来自哪个 composable、再看结构该用哪个原语”的判断方法你就能在自定义编辑器外壳中快速复刻出专业级属性面板同时保持代码的可测试性与可复用性。赞分享前端桌面应用AI 应用MCP 服务【免费下载链接】open-pencilAI-native design editor. Open-source Figma alternative.项目地址https://gitcode.com/gh_mirrors/op/open-pencil点击查看免费下载相关推荐OpenMetadata 邮件配置完整指南SMTP 参数解析、端口策略与源码实现原理OpenMetadata 邮件配置完整指南SMTP 参数解析、端口策略与源码实现原理 OpenMetadata 在用户注册、忘记密码、密码重置以及数据资产变更前端桌面应用AI 应用MCP 服务OpenPencil SDK 组合式 API 实战useStrokeControls 描边属性面板的完整指南OpenPencil SDK 组合式 API 实战useStrokeControls 描边属性面板的完整指南 useStrokeControls 是 Open前端桌面应用AI 应用MCP 服务OpenPencil Vue SDK 无样式外观控件AppearanceControlsRoot 插槽 API 与属性面板实战OpenPencil Vue SDK 无样式外观控件AppearanceControlsRoot 插槽 API 与属性面板实战 AppearanceContr前端桌面应用AI 应用MCP 服务上一篇CSS Scope Inline与Surreal构建无构建前端生态的最佳实践下一篇nix-darwin 高级用法自定义模块开发与扩展指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
