场景
工作室低码画布的TypeScript模型:UIElement分级,外接组件,和原型的表面组件系统.
序列化原型预览
PrototypeThumbnail 接受两个直播 IComponent 实例和原始 UIElement jSON文档中的数据。 在渲染时, Scene 使用元素的库合格 _derivedTypeId (或 componentName)来构建一个已注册的组件并复制其保存状态,在所有已命名的槽中递归式水分元素数组而不改变源文档。 没有注册的图书馆,它就会产生一个位置大小的占位符,而不是空的原型. 库注册本身不会触发 React 重置;在装入捆绑后重置缩略图以替换实际组件的占位符. 没有打开的动作,缩略图就是一个命名的、非焦点化的预览;有一个仍是一个编辑器打开按钮。 棋盘/文档阅读器不装入捆绑或依赖于 Studio Core.
布局预览 DTO
六个 StudioLayout.* 类型(Stack, (中文(简体) ), Row, (中文(简体) ), Grid, (中文(简体) ), Container, (中文(简体) ), Wrap,以及 Canvas)是后端预览 DTO. 它们来自现有的 FrameworkElement编号 :UIElement 级并使用相同的上线 ComponentName,继承 Properties,以及 Slots 形状为 ExternalComponent,所以通用的板预览可以绕行他们的被窝子. 他们故意不从 ExternalComponent:当前衍生型转换器将一个有已注册子类的基座作为歧视家族对待,然后不能将一个通名化 externalComponent 自己来 这个相容性边界避免了改变基本原理或打破已存在的通用组件"Dialog"和"确认Dialog"数据.
A 类 SceneDocument 是唯一可编辑的模型。 布局 DTO 仅用于遗留的板-预览投影;它们不是第二个场景模型,编辑器,解析器或持久性权威.
构成部分类别——如何运作
Component (单位:千美元) Component.ts)是每个原型表面组件(例如89 PrimeReact slapers under Source/PrimeReact/) (中文(简体) ). 它延伸 ExternalComponent 所以情况是适当的 UIElement 子类型,通过指令管道流动,而无需任何手动的线条格式转换.
为什么要扩展外部组件?
带元素使用的图标 UIElement[] 作为C# 和TypeScript两侧的类型。 在这设计之前, Component 是一个单独的类别 执行 IComponent 并且必须在转让前转换为有线格式的平原对象(toWireElement) (中文(简体) ). 这种转换是一种隐蔽了序列化故障的呼叫站点气味,要求每个消费者了解.
现在 Component extends ExternalComponent implements IComponent。一个 InputText 实例 UIElement ——直接通过:
command.elements = updatedElements as unknown as typeof command.elements;
这个 as unknown as 由于 TypeScript 看到 UIElement[] (与 id: Guid) 而编辑 PrototypeSurfaceElement 类型有 id: string。运行时值是正确的;只有已声明的类型在此边界上存在差异.
序列化如何运作
基本要素 JsonSerializer 走开 Object.getOwnPropertyNames(instance) 并按顺序列出每个财产。 设计 Component 确保只将 JSON 安全值显示为自己的属性 :
| 什麽 | 拥有财产? | 为什么 |
|---|---|---|
id | 是 — 字符串访问器通过 Object.defineProperty | C# (韩语) System.Text.Json 将 UUID 字符串解析为 Guid 自动 |
ZIndex, (中文(简体) ), anchoring, (中文(简体) ), width, (中文(简体) ), height, (中文(简体) ), name, (中文(简体) ), properties, (中文(简体) ), slots, (中文(简体) ), componentName | 是——设置在 initialize() | 均为纯值; 安全序列化 |
_derivedTypeId | 是——明确载于 initialize() | 告诉基本原理 淡化为 ExternalComponent 在服务器上 |
toolbarIcon | 没有 - 原型车 | React-icons 组件是具有 prototype.constructor 自引用; 序列化它们会导致无限的重复. 做一个原型手 让他们远离 Object.getOwnPropertyNames 完全没有 |
RenderPrototype | 否-抽象原型方法 | 相同的理由;原型上的方法从来不是实例的自有财产 |
label, (中文(简体) ), position, (中文(简体) ), size, (中文(简体) ), children, (中文(简体) ), type | 没有——原型取取取器 | 已计算桥; 不序列数据 |
Id桥
SceneObject 声明 id: Guid (通过) @field(Guid)) (中文(简体) ). IComponent 声明 id: string。构造器以平弦存取器取代类场拥有的财产:
let _id = '';
Object.defineProperty(this, 'id', {
get() { return _id; },
set(value: string) { _id = String(value ?? ''); },
enumerable: true,
configurable: true,
});
序列器读取字符串 UUID; C# 将其描述为 Guid。比较ID使用的编辑器代码 string 平等贯穿一切.
这个 _derivedTypeId 拥有财产
DerivedType.get(constructor) 用途 Reflect.getOwnMetadata,这确实 没有 穿越原型链。 这个 @derivedType('externalComponent') 装饰器打开了 ExternalComponent这样 DerivedType.get(InputText) 返回时 undefined如果没有明确的自身财产,JSON产出将不存在 _derivedTypeId c#破坏者不知道建造一个 ExternalComponent。 。 。 .
initialize() 直接设定:
(this as unknown as Record<string, unknown>)['_derivedTypeId'] = 'externalComponent';
类型密钥
之后 initialize(), (中文(简体) ), componentName 更新到完整的符合图书馆条件的密钥('PrimeReact.InputText') (中文(简体) ). 在此之前 initialize() 子类类字段有短名( q)'InputText') (中文(简体) ). 这个 type getter 总是通过分割返回完全合格的密钥 . 并重新与 library数字 :
get type(): string {
const cn = this.componentName ?? '';
const shortName = cn.split('.').pop() ?? cn;
return this.library ? `${this.library}.${shortName}` : shortName;
}
子类作者
执行这些成员:
export default class InputText extends Component {
readonly componentName = 'InputText'; // short name; initialize() stores the full key
readonly category = 'Form';
readonly library = 'PrimeReact';
readonly initialSize = { width: 220, height: 42 };
readonly resizeBehavior = 'horizontal' as const;
// MUST be a getter — not a class field.
// Class fields are own instance properties and cause infinite recursion in Fundamentals' serializer.
override get toolbarIcon() { return FaKeyboard; }
RenderPrototype({ label }: PrototypeComponentRenderProps): ReactNode { ... }
}
toolbarIcon 必须 是一个 override get. 类领域(readonly toolbarIcon = FaKeyboard制造( ) FaKeyboard 财产。 基斯的序列器然后调用 Object.getOwnPropertyNames(FaKeyboard) 包含 prototype,其 constructor 点回 FaKeyboard,导致无限制的复发和 a RangeError。 。 。 .