☰
Open-Pencil Vue SDK 实战:用 useColorVariableBinding 实现填充与描边的颜色变量绑定
2026/9/28 21:13:27 网站建设 项目流程
  • 前端
  • 桌面应用
  • AI 应用
  • MCP 服务

【免费下载链接】open-pencil

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

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

useColorVariableBinding(kind)是 Open-Pencil Vue SDK 提供的一个高级组合式 API,专为填充(fills)与描边(strokes)等颜色编辑 UI 设计:它把「在节点上查找、绑定、解绑颜色变量」这组高频操作封装成一组可直接调用的函数,让自定义属性面板只需几行代码就能把普通色块升级为可绑定设计变量的颜色控件。读完本文,你将掌握该 API 的完整签名与返回结构、它与useFillControls/useStrokeControls的分工关系,以及它背后在场景图(scene-graph)层的绑定校验与状态同步原理。

概览:这个 API 解决什么问题

在设计编辑器中,一个节点的fills[0].color可能来自两种来源:要么是写死的字面颜色值,要么是通过变量系统与某个COLOR类型变量建立关联(binding)。一旦建立绑定,修改变量即可批量驱动所有引用它的节点——这正是「变量驱动设计」的核心能力。

useColorVariableBinding(kind)把「查找变量 → 绑定 → 解绑 → 按需新建变量并绑定」这一完整流程收拢成一个 composable,签名如下(源码见 packages/vue/src/controls/color-variable-binding/use.ts):

useColorVariableBinding(kind: 'fills' | 'strokes')

kind决定它操作的是填充还是描边,并直接决定绑定路径(binding path)的形态。从实现看,该 composable 内部通过useVariableBinding构造了绑定描述:

// packages/vue/src/controls/color-variable-binding/use.ts(节选) const binding = useVariableBinding({ type: 'COLOR', path: (index) => `${kind}/${index}/color` })

即:type: 'COLOR'限定只与颜色类型变量交互;path: (index) => \${kind}/${index}/color`把第index个填充/描边的颜色字段映射为形如fills/0/color、strokes/1/color的绑定路径,这与场景图中boundVariables的键格式一一对应(见 [packages/scene-graph/src/types.ts](https://link.gitcode.com/i/fca4ff82ed8d83c3b7f644e1387da9af) 的boundVariables: Record<string, string>` 定义)。

基础用法

在 Vue 组件中直接导入并调用即可:

import { useColorVariableBinding } from '@open-pencil/vue' const fillBinding = useColorVariableBinding('fills') const strokeBinding = useColorVariableBinding('strokes')

典型的接入场景是构建支持设计变量的颜色控件:fillBinding负责填充色列表的变量绑定,strokeBinding负责描边色。两者返回的 API 完全同构,只是kind不同,因此可以共用同一套 UI 逻辑。

返回对象:完整的变量绑定工具箱

useColorVariableBinding展开底层useVariableBinding的全部能力,并额外补充颜色专属函数。其返回值包含以下成员(对应 packages/vue/src/controls/variable-binding/use.ts 与颜色专属包装):

成员类型说明
storeEditor通过useEditor()获取的编辑器实例,用于读取节点与变量
searchTermRef<string>变量搜索关键词,驱动filteredVariables
variablesComputedRef<Variable[]>当前文档中全部COLOR类型变量(响应式)
filteredVariablesComputedRef<Variable[]>按名称过滤后的变量列表
colorVariables同variables颜色变量列表的别名,语义更明确
bindingPath(index?) => string生成当前kind的绑定路径,如fills/0/color
getBoundVariable(nodeId, index?) => Variable \| undefined读取某节点指定索引处已绑定的变量
getBindingState(nodeIds, index?) => 'unbound' \| 'bound' \| 'mixed'多选场景下计算绑定状态
bindVariable(nodeId, index, variableId) => void将变量绑定到节点的第index个填充/描边颜色
unbindVariable(nodeId, index) => void解除指定索引处的绑定
createAndBindVariable(nodeId, index, color, name?) => void新建颜色变量并立即绑定

其中颜色专属的部分是:

// packages/vue/src/controls/color-variable-binding/use.ts(节选) function createAndBindVariable( nodeId: string, index: number, color: Color, name = FALLBACK_COLOR_VARIABLE_NAME // 'New color' ) { const collection = colorCollection() const id = `var:${randomHex(8)}` binding.store.addVariable({ id, name: name.trim() || FALLBACK_COLOR_VARIABLE_NAME, type: 'COLOR', collectionId: collection.id, valuesByMode: Object.fromEntries(collection.modes.map((mode) => [mode.modeId, color])), description: '', hiddenFromPublishing: false }) binding.bindVariable(nodeId, id, index) }

注意createAndBindVariable的返回结构中有意重排了参数:对外是(nodeId, index, variableId),而底层bindVariable内部调用的是(nodeId, variableId, index)顺序,封装层已替你处理好映射(见 packages/vue/src/controls/color-variable-binding/use.ts)。使用返回值中的bindVariable/unbindVariable时,按本表的签名传参即可,无需关心底层顺序。

实战:构建支持变量绑定的填充控件

结合 useFillControls 与 FillRoot,可以组装一个完整的填充编辑区。useFillControls本身就是useColorVariableBinding('fills')的薄封装,额外附带defaultFill默认填充值(源码见 packages/vue/src/controls/fill/use.ts):

import { useFillControls } from '@open-pencil/vue' const fills = useFillControls() // fills 展开自 useColorVariableBinding('fills'), // 额外提供 defaultFill(来自 DEFAULT_SHAPE_FILL 常量) // 新增一行填充 propertyList.add(fills.defaultFill) // 将第 0 个填充绑定到某个颜色变量 fills.bindVariable(activeNodeId, 0, variableId) // 解绑第 0 个填充 fills.unbindVariable(activeNodeId, 0) // 把当前填充色保存为变量并立即绑定 fills.createAndBindVariable(activeNodeId, 0, { r: 0.2, g: 0.4, b: 0.8, a: 1 })

同理,useStrokeControls 负责描边的对齐、边、端点、连接等几何属性;若你的描边颜色编辑器也需要变量能力,可自行在其上组合useColorVariableBinding('strokes')。两者与useColorVariableBinding的分工是:前者管「面板业务状态」,后者管「颜色与变量之间的绑定数据」。

结合 FillRoot 渲染绑定状态

Open-Pencil 还提供了无头组件 FillRoot(导出见 packages/vue/src/primitives/Fill/index.ts)。将useFillControls返回的colorVariables/filteredVariables传入填充选择器,即可渲染一个既能选字面色、又能搜索并绑定变量的控件:

<script setup lang="ts"> import { useFillControls } from '@open-pencil/vue' const fills = useFillControls() </script> <template> <!-- 变量搜索框 --> <input v-model="fills.searchTerm" placeholder="搜索颜色变量" /> <!-- 过滤后的变量列表 --> <div v-for="variable in fills.filteredVariables" :key="variable.id"> {{ variable.name }} <!-- 绑定到当前选中节点的第 0 个填充 --> <button @click="fills.bindVariable(activeNodeId, 0, variable.id)">绑定</button> </div> </template>

多选状态:unbound / bound / mixed

getBindingState是处理多选节点时的关键函数。其逻辑(见 packages/vue/src/controls/variable-binding/use.ts)为:

  • 收集每个节点在指定索引处的绑定变量 ID;
  • 若各节点绑定不同变量(ID 集合大小 > 1),返回'mixed';
  • 若某个节点未绑定(ID 为undefined),返回'unbound';
  • 否则返回'bound'。

UI 可根据该状态切换控件外观:unbound显示字面色值、bound显示变量名并提供解绑入口、mixed显示混合占位。这一状态机与属性面板中「多选混合值」的通用约定一致。

搜索与过滤:不区分大小写的变量查询

searchTerm与filteredVariables实现了内置的变量搜索。底层使用reka-ui的useFilter({ sensitivity: 'base' })做不区分大小写的名称匹配(见 packages/vue/src/controls/variable-binding/use.ts):

const filteredVariables = computed(() => { if (!searchTerm.value) return variables.value return variables.value.filter((variable) => contains(variable.name, searchTerm.value)) })

variables本身通过useSceneComputed派生:该封装会追踪sceneVersion、selectedIds、currentPageId等场景状态(见 packages/vue/src/internal/scene-computed/use.ts),因此文档中任何颜色变量的新增、重命名或删除都会自动触发列表刷新,无需手动维护响应式依赖。

底层原理:场景图中的变量绑定与校验

useColorVariableBinding最终通过store.bindVariable/store.unbindVariable落到场景图层。这两个方法定义在 packages/scene-graph/src/index.ts,实现在 packages/scene-graph/src/variables.ts。绑定过程包含严格的类型与范围校验:

  • 变量必须存在:variableId在graph.variables中不存在时直接抛出Variable "xxx" not found;
  • 颜色字段必须绑COLOR变量:绑定路径匹配/^(fills|strokes)\/(\d+)\/color$/时,若变量类型不是COLOR,抛出Cannot bind ${type} variable to color field "${field}";
  • 索引必须落在数组内:如fills/2/color但节点当前只有 1 个填充,抛出Index 2 out of range for fills (length 1);
  • 自动清理顶层死绑定:设置索引级绑定时,会删除同 key 的顶层绑定(例如旧的fills键),避免冲突;
  • 其他字段的类型约束:标量字段(如width、opacity)要求FLOAT,fontFamily要求STRING,visible要求BOOLEAN,均有对应的字段白名单(见 packages/scene-graph/src/variables.ts)。

每次绑定/解绑后都会发出node:updated事件并同步实例覆盖(markBoundVariablesOverrideOnInstance),保证画布与属性面板即时刷新。unbindVariable则相对轻量:字段不存在时直接返回(packages/scene-graph/src/variables.ts)。

颜色变量的存取与解析

colorCollection()负责定位或创建颜色变量所属的集合:优先复用「包含至少一个COLOR类型变量」的现有集合;若不存在,则新建名为Colors、含默认Mode 1模式的集合(源码见 packages/vue/src/controls/color-variable-binding/use.ts)。createAndBindVariable会为该集合的每个 mode 写入同一份颜色值(valuesByMode),因此多模式下也能获得一致的初始表现。

在读取侧,packages/scene-graph/src/variables.ts 提供了完整的解析链:resolveVariable按「节点 mode → 集合活跃 mode → 默认 mode → 任意值」的顺序取值,并支持别名(alias)递归解析;resolveColorVariableForNode则结合节点的variableModes为指定节点解析出实际颜色。整个变量系统的数据结构以Variable与VariableCollection为核心(见 packages/scene-graph/src/types.ts),boundVariables记录「字段 → 变量 ID」的映射。

与其他 API 的关系

useColorVariableBinding属于 SDK 中「公开但更专门化」的高级 API(见 packages/docs/programmable/sdk/api/advanced/index.md 的 Advanced 分组)。它的同级与上层 API 包括:

  • useFillControls:填充面板组合式 API,内部直接复用useColorVariableBinding('fills');
  • useStrokeControls:描边面板组合式 API,管理对齐、边、端点等属性;
  • FillRoot:填充渲染用的无头组件;
  • useNumberVariableBinding:同类 API,面向FLOAT数值字段(如width、cornerRadius、opacity),可用于构建数值变量绑定控件;
  • useVariableBinding:以上两者的公共底层,接受type与path两个选项,是理解整个变量绑定体系的最佳入口。

这些 API 均从 packages/vue/src/index.ts 统一导出,安装@open-pencil/vue后即可使用;导出清单亦记录在 packages/vue/README.md 的 Advanced API 章节。若你的控件需要更细粒度的「绑定供给」能力(例如指定目标字段、编辑策略与变更来源追踪),可进一步研究 useColorBindingProvider 及其配套的 binding-provider 模块,它提供了createAndBindColorVariable、useColorBindingProvider等面向复杂绑定场景的工具。

小结

useColorVariableBinding是一个「小而专」的 composable:入口只需一个'fills' | 'strokes'参数,即可获得搜索、绑定、解绑、新建并绑定一条龙的完整变量绑定能力。配合useFillControls的defaultFill与FillRoot等无头组件,你可以在 Open-Pencil 的 Vue SDK 之上快速搭建出符合设计工具习惯、支持多选混合状态与实时变量同步的颜色编辑面板。

  • 前端
  • 桌面应用
  • AI 应用
  • MCP 服务

【免费下载链接】open-pencil

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

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询