ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

lowcode-engine 属性模型(Prop)API 全解析:从节点属性读写到 Schema 导出

lowcode-engine 属性模型(Prop)API 全解析:从节点属性读写到 Schema 导出 lowcode-engine 属性模型PropAPI 全解析从节点属性读写到 Schema 导出【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine本文围绕低代码引擎lowcode-engine中的属性模型PropIPublicModelProp展开系统讲解其属性成员与全部公开方法并结合仓库源码揭示Prop在节点文档模型中的底层实现、值类型分类、响应式更新与 Schema 导出机制。读完本文你将掌握在插件、设置面板或扩展中通过Prop读取/修改/删除节点属性、操作 Slot、以及按不同阶段导出 Schema 的完整实战方案。一、认识属性模型 Prop在 lowcode-engine 的文档模型中节点Node的属性props以一棵属性树的形式组织根上是节点的一组Props每一个叶子或分支单元就是一个Prop。Prop是访问节点属性值的最小、最直接的入口例如按钮组件的size、type、children页面组件的loop、condition乃至扩展配置项最终都以Prop的形态挂载在节点上。Prop模型在官方 API 类型定义中为IPublicModelProp自v1.0.0起随引擎对外暴露对应接口定义见 packages/types/src/shell/model/prop.ts。该接口经过「类型层 → Shell 层 → 设计器内核层」的三级封装类型层IPublicModelProp定义对外契约属性与方法签名Shell 层packages/shell/src/model/prop.ts中的Prop类将内部实现包装为公共 API并负责把内部INode转换成对外可见的IPublicModelNode内核层packages/designer/src/document/node/props/prop.ts中的Prop类基于 mobx 实现真正的属性存储、类型推断、响应式变更与导出逻辑。文章后续章节会同时给出「API 用法」与「源码实现」方便你在使用 API 的同时理解其底层原理。二、获取 Prop 实例的入口在实际开发中Prop实例通常不是直接new出来的而是从节点上获取。在 packages/shell/src/model/node.ts 中节点提供了一组属性访问方法方法作用对应 Prop 操作node.getProps()获取节点全部属性集合IPublicModelProps——node.getProp(path, createIfNone?)按路径获取单个Prop默认不存在时自动创建ShellProp.create(...)node.getPropValue(path)直接读取属性值等价于getProp(path, false)?.getValue()getValuenode.setPropValue(path, value)直接写入属性值setValuenode.getExtraProp(path, createIfNone?)获取扩展属性PropShellProp.create(...)node.getExtraPropValue(path)读取扩展属性值getValuenode.setExtraPropValue(path, value)写入扩展属性值setValue路径支持a.b.c形式的嵌套写法也支持数组下标例如getProp(props.dataSource)。扩展属性extra props是 lowcode-engine 里一类特殊的属性它们以___前缀存放用于承载非标准 props 之外的数据如设计器内部状态。在内核层 packages/designer/src/document/node/props/props.ts 中可以看到getConvertedExtraKey会为扩展 key 拼接___前缀形如___key___getOriginalExtraKey则负责还原。当你调用getExtraProp系列方法时拿到的同样是一个Prop实例因此本文介绍的全部 Prop 能力同样适用于扩展属性。三、属性成员PropertiesIPublicModelProp对外暴露以下只读属性均以内核 Prop 的数据为来源。id当前 Prop 的唯一标识。get id(): string;在内核实现中id 由uniqueId(prop$)生成见 packages/designer/src/document/node/props/prop.ts即每个 Prop 实例拥有形如prop$xxxx的全局唯一 id可用于调试追踪或作为 React key 使用。key当前 Prop 的键值。对于根属性集合中的属性key 即属性名对于嵌套属性key 是其在父对象中的字段名或数组下标。get key(): string | number | undefined;需要注意key与path的区别key只代表自身的一级键名path则代表从根到自身的完整路径。此外内核层还有一个细节key以!开头时该 Prop 被判定为虚拟属性isVirtual()见 prop.ts。path返回当前 Prop 的完整路径类型为string[]。get path(): string[];内核实现为逐级拼接父路径get path(): string[] { return (this.parent.path || []).concat(this.key as string); }例如组件节点props.align这个 Prop其path为[align]若嵌套在props.list.data[0]下则 path 为[list, data, 0]。Shell 层的get path()直接透传内核值见 packages/shell/src/model/prop.ts。node返回当前 Prop 所属的节点实例。get node(): IPublicModelNode | null;Shell 层实现中通过ShellNode.create(this[propSymbol].getNode())将内部节点包装为对外节点模型见 packages/shell/src/model/prop.ts对应内核getNode()返回this.owner。这在「属性变更后需要联动操作节点」的场景中非常实用例如根据某个属性值动态切换节点状态。slotNode当当前 Prop 代表一个 Slot插槽时返回对应的插槽节点否则返回null或undefined。get slotNode(): IPublicModelNode | undefined | null;Slot 是低代码 schema 中一种特殊属性值JSSlot用于表达「子组件容器/模板片段」。内核层setAsSlot会把JSSlot数据转换为一个componentName: Slot的子节点并挂到文档上见 prop.ts随后slotNode即返回该插槽节点。需要说明的是类型接口注释中标明该属性since v1.1.0而当前文档页标注整体 API 自 v1.0.0 可用使用时请以你所依赖版本的类型声明为准。isProp用于标识「这是一个 Prop」恒为true。get isProp(): boolean;该属性在类型接口中标注为experimental内核层直接声明readonly isProp true。它是运行时类型守卫isProp(obj)的依据源码中多处通过obj obj.isProp判断一个值是否为 Prop 实例。四、核心方法MethodssetValue设置值/** * 设置值 * set value for this prop * param val */ setValue(val: IPublicTypeCompositeValue): void;setValue接收一个复合类型值IPublicTypeCompositeValue。该类型定义于 packages/types/src/shell/type/composite-value.ts是以下几类值的联合export type IPublicTypeCompositeValue IPublicTypeJSONValue | IPublicTypeJSExpression | IPublicTypeJSFunction | IPublicTypeJSSlot | IPublicTypeCompositeArray | IPublicTypeCompositeObject;即普通 JSON 值字符串/数字/布尔/null、JS 表达式JSExpression、JS 函数JSFunction、插槽JSSlot、复合数组、复合对象。内核setValue会根据传入值的类型自动推断 Prop 的值类型ValueTypes见 prop.ts 与 L353-L390传入值推断的type说明null/undefined/ 字符串 / 数字 / 布尔literal字面量普通数组list列表子项为索引 Prop包含type: JSSlot的对象slot插槽会触发setAsSlot创建 Slot 节点包含type: JSExpression的对象expression表达式其余普通对象map字典子项为字段 Prop其他类型如函数等expression自动包装为JSExpression并序列化为源码字符串setValue每次写入都会清空代码缓存_code、销毁旧的子 Prop 树dispose、重建 items 以维持响应式链路并通过emitChange触发GlobalEvent.Node.Prop.InnerChange事件与节点的emitPropChange见 prop.ts。这意味着对 Prop 的修改会实时驱动设计器 UI 与渲染器同步更新。典型用法// 修改节点属性 node.getProp(size)?.setValue(large); // 写入表达式值 node.getProp(visible)?.setValue({ type: JSExpression, value: this.state.visible, }); // 写入嵌套对象 node.getProp(style)?.setValue({ color: #fff, fontSize: 14 });getValue获取值/** * 获取值 * get value of this prop */ getValue(): any;返回当前 Prop 的值。Shell 层实现直接调用内核getValue()而内核getValue()等价于以Serilize序列化阶段导出值见 prop.tsgetValue(): IPublicTypeCompositeValue { return this.export(IPublicEnumTransformStage.Serilize); }即getValue()拿到的值遵循「序列化阶段」的导出规则字面量原样返回、表达式返回{ type: JSExpression, value: ... }结构、插槽返回{ type: JSSlot, ... }结构、map/list 递归导出子项unset的子项会被跳过。remove移除值/** * 移除值 * remove value of this prop * since v1.0.16 */ remove(): void;remove()自v1.0.16起提供作用是将当前 Prop 从父级移除并取消其值。内核实现prop.tsaction remove() { this.parent.delete(this); // 从父 props/items 中摘除 this.unset(); // 将类型置为 unset }其中parent.delete会从_items中 splice 掉自身并从_maps中删除 key随后unset将_type置为unset并触发变更事件。注意remove之后该 Prop 实例仍可被引用但其值已变为「未设置」状态导出时会被过滤掉。exportSchema按阶段导出值/** * 导出值 * export schema * param stage */ exportSchema(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue;exportSchema用于按指定的转换阶段TransformStage导出属性值是 Prop 层面对 schema 序列化的统一入口。Shell 层实现为packages/shell/src/model/prop.tsexportSchema(stage: IPublicEnumTransformStage IPublicEnumTransformStage.Render) { return this[propSymbol].export(stage); }阶段枚举定义于 packages/types/src/shell/enum/transform-stage.tsexport enum IPublicEnumTransformStage { Render render, // 渲染阶段 Serilize serilize, // 序列化阶段注意官方拼写为 Serilize Save save, // 保存阶段 Clone clone, // 克隆阶段 Init init, // 初始化阶段 Upgrade upgrade, // 升级阶段 }同一个属性在不同阶段下导出的形态可能不同典型差异见内核export实现 prop.ts___condition___特殊处理在Render阶段若引擎未开启enableCondition配置该 prop 强制导出为true设计器默认展示所有组件否则返回原值unset类型任何阶段均导出undefinedslot类型Render阶段导出{ type: JSSlot, params, value: 完整SlotSchema, id }其余阶段导出{ type: JSSlot, params, value: children, title, name, id }——即渲染阶段需要完整的插槽结构而保存阶段聚焦于 children 与元信息map/list类型递归调用子 Prop 的export(stage)unset的 map 子项被跳过list 子项按序导出。使用示例// 获取渲染阶段的值适合传给渲染器 const renderValue prop.exportSchema(IPublicEnumTransformStage.Render); // 获取保存阶段的值适合持久化到 schema 文件 const saveValue prop.exportSchema(IPublicEnumTransformStage.Save);五、从源码看 Prop 的生命周期与响应式设计1. 值类型驱动的内部结构Prop 并非「一把梭」地保存值而是通过_typeunset | literal | map | list | expression | slot决定如何组织内部数据literal/expression直接持有原始值map维护子 Prop 的items与_mapskey → Prop提供get/set/has/forEach/map等字典操作list子 Prop 按数组下标组织支持add追加、set(idx, v)按下标写入、get(idx)读取slot持有_slotNode插槽节点。这套设计让Prop既是「值容器」又是「属性子树」天然支持a.b[0].c这种深层路径的定位与读写。内核中get(path, createIfNone)还会自动解析点分路径并在不存在时按需创建中间 Prop见 prop.ts。2. 响应式更新链路Prop的所有可变操作setValue、set、add、unset、remove等都标注了action字段使用obx/computed装饰底层基于 mobx 观察机制。setValue时有一个值得关注的细节源码注释也特别说明重新赋值会销毁旧子 Prop 并新建若直接替换外部observer/reaction监听的旧子 Prop 会断链因此内核通过_maps缓存机制尽量复用已存在的子 Prop、保留响应式关系见 prop.ts 的注释说明。属性变更还会通过emitChange广播事件payload 包含{ key, prop, oldValue, newValue }并分别触发引擎级Node.Prop.InnerChange全局事件与节点级emitPropChange。这正是「在设置面板中修改属性 → 画布实时刷新」这条链路的底层保证。3. 与其他模型的协作与Node通过node/getNode()回溯所属节点与PropsProp 挂在IProps属性集合之下Props负责整个集合的导入import、合并merge与导出export见 packages/designer/src/document/node/props/props.ts与SettingFieldProp 的getPropValue/setPropValue/clearPropValue直接对标SettingTarget的取值/赋值/清值语义见 prop.ts设置面板的字段绑定底层即依赖这一能力。六、实战小结需求推荐 API读取节点某个属性值node.getPropValue(size)或prop.getValue()修改节点某个属性值node.setPropValue(size, large)或prop.setValue(...)按路径访问嵌套属性node.getProp(style.color)、prop.get(list[0])风格路径删除一个属性prop.remove()v1.0.16判断属性是否未设置内核prop.isUnset()Shell 层可借由getValue()为undefined判断读取插槽对应节点prop.slotNode按阶段导出属性prop.exportSchema(IPublicEnumTransformStage.Save / Render / ...)监听属性变更监听GlobalEvent.Node.Prop.InnerChange事件或节点emitPropChange读写扩展属性node.getExtraProp/node.setExtraPropValue内部仍为 Prop以上所有能力均可在插件、设置面板扩展、命令处理器中直接使用先通过documentModel或事件回调拿到节点再经由node.getProp(...)获得Prop实例即可完成对设计态节点属性的全生命周期操作。若要进一步研究可继续阅读对外类型契约packages/types/src/shell/model/prop.tsShell 层包装实现packages/shell/src/model/prop.ts内核完整实现值类型、响应式、导出逻辑packages/designer/src/document/node/props/prop.ts属性集合 Propspackages/designer/src/document/node/props/props.ts复合值类型定义packages/types/src/shell/type/composite-value.ts转换阶段枚举packages/types/src/shell/enum/transform-stage.ts【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表