Style Resolver:Schema 驱动低代码平台的样式能力设计

一、背景

对于 Schema 驱动的低代码平台,style 是协议的必要组成部分。如果平台用 Schema 描述页面结构、属性、数据和行为,却不能对样式进行协议化声明与运行时解析,那么它的页面描述能力就是不完整的。

低代码的本质决定了样式必须走完整的协议链路:Schema 静态声明 → Runtime 解释执行 → Renderer 呈现。同时,Designer 必须能够产出这份样式声明------无论入口来自 AI 生成、源码编辑,还是属性面板。

Style Resolver 的引入不是孤立的"样式优化",而是平台能力模型的必要补全。


二、技术方案设计

2.1 Schema 中的 style 与四层链路

style 定义在 Schema 顶层,表示页面的视觉样式声明。

围绕 schema.style,样式链路分成四层:

text 复制代码
Designer
  负责产生和编辑样式声明
        ↓
Schema
  负责持久化 style 定义
        ↓
Runtime
  负责解析 style,得到可运行的样式结果
        ↓
Renderer
  负责把解析结果呈现到真实 DOM

2.2 Runtime 的 Style Resolver 能力

schema.style 只是声明,不是可渲染结果。Runtime 需要具备 Style Resolver 能力,把声明转换成可消费的样式对象。

这层能力解决三件事:

  • 解析样式值(静态值和表达式)
  • 过滤不支持的样式字段,清理无效结果(undefined等数据)

2.3 受控的协议边界

低代码平台不能把任意 CSS 属性无约束地开放到 Schema 中,否则协议失去边界,各层也无法形成统一认知。

样式需要是受控的:平台声明支持哪些字段,Runtime 只解析这些字段,Designer 只暴露这些字段的编辑入口。

这样设计的价值:

  • 协议边界清晰,避免无效或不安全字段进入渲染链路
  • 扩展有统一基线,样式能力可持续演进

这也带来一个约束:新增样式属性需要先纳入协议边界。对于普通样式字段,扩展的是协议元信息与字段声明;对涉及特殊语义或转换规则的字段,还需要扩展 Runtime 逻辑。


三、具体实现

3.1 协议层:新增 style 字段

Schema 接口中添加:

ts 复制代码
export interface Schema {
  id: string
  componentName: string
  props?: Record<string, any>
  style?: StyleSchema  // 新增,StyleSchema 是一个受控的协议,只允许平台声明的样式字段
  // ...
}

3.2 Runtime 层:实现 resolveStyle

目标:把 schema.style 从"样式声明"转换成"Renderer 可直接消费的样式结果"。

表达式解析带来的效果,是让样式不再只是固定值,而是可以跟着页面数据和状态动态变化。例如:

  • color: "{{state.theme === 'dark' ? '#fff' : '#111'}}",可以根据主题切换文字颜色
  • display: "{{state.visible ? 'block' : 'none'}}",可以根据状态控制显示与隐藏

它背后依赖的是 Runtime 内部的表达式求值能力,整体原理可参考 低代码 Expression Engine:一个微型表达式解释器的设计

resolveStyle 在这一层主要做三件事:

  • 遍历 schema.style,识别每一个样式字段
  • 对每个值做解析,静态值直接使用,表达式值交给表达式引擎求值
  • 清理无效结果(undefined / null / 空字符),产出稳定的 resolvedStyle

对于白名单之外的字段,基本思路是按原字段名直接透传到 resolvedStyle,让自定义样式、动画、定位等能力也能落到页面上。

解析结果挂到节点解析结果上,随链路继续向下传递给 Renderer。

3.3 Renderer 层:传递 style prop

tsx 复制代码
<Component {...item.resolvedProps} style={item.resolvedStyle} />

3.4 Designer 层:样式的产出入口

schema.style 的产出入口有三个:

属性面板(StyleSetter) :围绕 schema.style 做"读取字段 → 渲染编辑器 → 响应修改 → 回写 Schema"的闭环。以 fontSize 为例:

text 复制代码
schema.style.fontSize
   ↓ 读取
PropertyPanel / StyleSetter 识别字段,渲染 NumberSetter
   ↓ 用户输入
onChange(newValue)  →  触发 Command  →  回写 schema.style.fontSize

源码编辑 :用户直接编辑 Schema JSON,手动维护 style 字段。

AI 生成 :System Prompt 中明确约束 AI 把视觉样式输出到 style 字段,而非 props,AI 生成的 Schema 天然携带 schema.style


四、踩过的坑

4.1 接口边界不清:resolveObject 不该对外暴露

最初将 resolveStyleresolveObject 同时作为公共接口,调用方不知道该用哪个,技术方案文档里也出现了"先调 resolveObject 再调 resolveStyle"的混乱描述。

问题根因在于没有区分"公共接口"和"内部工具"的职责:

  • 公共接口resolveStyle / resolveProps / resolveEvents):面向具体场景,语义明确,调用方直接使用
  • 内部工具resolveObject):通用的对象遍历与解析逻辑,只供上述接口内部复用,不对外暴露

明确这个边界后,调用方只看到语义清晰的公共接口,内部实现细节不再泄漏到外部。


4.2 props 残留样式的覆盖问题

引入 schema.style 后,StyleSetter 的修改却不生效------props: { fontSize: 16 } 会直接压过 style: { fontSize: 20 }。原因是物料组件还在从 props 解构样式字段并合并到 style,导致 props 里的值优先级更高。

面对这个问题,有三种处理思路:

  • 方案一:运行时 merge ------解析时把 schema.style 和 props 里的样式字段合并,schema.style 优先。两套数据共存,无需迁移,但协议职责边界模糊。
  • 方案二:schema.style 覆盖 ------Renderer 层让 resolvedStyle 覆盖 props 里的同名字段。实现最简单,但 props 和 style 的边界还是不清晰,只是优先级问题被掩盖了。
  • 方案三:全链路迁移 ------彻底清理 props 中的样式字段,schema.style 作为唯一来源,同步更新存量数据、AI Prompt 和物料组件。

项目没有历史数据包袱,我选了 方案三。代价是要同步改三处,但换来的是协议彻底干净:props 只承载业务属性,style 只承载样式属性,两者职责清晰,"干净利落"的协议为以后调试、问题排查和能力演进提供了基础。


五、成果与展望(todo)

5.1 成果

Runtime 层的 Style Resolver V1 已经形成完整闭环:Designer 负责产出和修改 schema.style,Runtime 负责解析,Renderer 负责最终呈现。

这意味着样式能力正式成为低代码平台的一条标准链路,属性设置到页面展示之间有了统一、稳定的实现方式。

最终效果:

5.2 展望

后续的演进方向:让 schema.style 不只是能表达基础样式,还能逐步承载主题、设计变量、自定义样式、响应式,甚至弹窗、脱离文档流、动画等更复杂的视觉效果。

我希望最终达到的效果是:基于这套能力,低代码平台不只可以搭普通页面,还可以做出布局复杂、视觉丰富、样式炫彩、交互更强的应用页面。

相关推荐
SL_staff8 天前
3周搭完MES系统:JVS低代码+JVS-IoT物联网的实战记录
java·前端·低代码
AprChell10 天前
低代码设计器和低代码设计引擎架构综述
前端·vue.js·低代码
Kagol14 天前
NocoBase 开源项目源码深度分析
低代码
UXbot16 天前
帮助企业低门槛开展AI应用开发的平台推荐
前端·低代码·ui·交互·产品经理·原型模式·web app
盟接之桥16 天前
电子数据交换(EDI)|制造业汽车零配件场景方案
大数据·网络·人工智能·安全·低代码·汽车·制造
UXbot17 天前
如何选择适合公司项目的UI设计工具?企业选型指南
前端·低代码·ui·团队开发·原型模式·设计规范·web app
UXbot17 天前
原型设计工具如何帮助新人快速进入产品行业?
前端·低代码·ui·交互·团队开发·原型模式·web app
NocoBase17 天前
程序员和软件还有前途吗 —— 从 NocoBase 收入再翻倍谈起
低代码·ai·开源·无代码·管理工具·内部工具·无代码开发平台
盟接之桥17 天前
制造业汽车零配件EDI软件场景方案
网络·安全·低代码·汽车·制造