之前遇到一个需求,需要动态的生成上百个查询条件的动态表单,当时用JSON数据生成页面。手动的配置JSON数据来生成动态表单。在此的基础上进行优化和升级,引入物料平台和拖拽的功能,就是一个可视化的页面编辑器
我们日常工作中除了CRUD也可以发现一些技术上找一些有意思的点。
其实低代码原理很简单,就是一个动态注册,vue3使用defineAsyncComponent。动态的加载文件,动态的注册组件。原理很简单,难点是怎么适配不同的页面需要,如何最大程度的简化通用页面的开发过程。同时也在考虑配合AI会不会有更好的效果,毕竟目前AI开发代码能力都很强,如果有一套可以堆积木生成页面的平台,交给AI是不是工作会变得更简单
低代码平台思路与方向
首先低代码平台一般有三部分组成
- 物料平台
- 渲染器
- 控制面板
左中右三部分,左边的是物料平台可以加载不同的组件,就像商店的货架,货架上的物品随意挑选,选中了就可以拖拽到中间的渲染器中进行渲染。物料平台主要负责统一规划不同渠道来的组件库,将他们统一转化成渲染器支持的状态。
通过统一的注册机制,可以方便地添加新组件,只需要提供符合规范的描述文件,就可以利用AI或者手工配置。组件属性采用开放结构,支持自定义扩展。
物料平台
组件库是低代码平台的前提准备 里面存放了由协议规范的可供进行拖拉拽的组件内容
- 完全解耦:物料平台与渲染平台完全分离,可独立部署
- 描述驱动:物料平台只负责输出标准描述文件,不处理组件注册
- 按需注册:组件只在渲染器实际使用时才进行注册
- 避免重复:同一组件仅注册一次,防止性能浪费
- 远程加载:支持从远程服务器加载物料描述
物料平台只负责输出描述文件,交给渲染器去渲染页面,所以物料平台和渲染器因该是解耦的独立存在,里面进入什么组件不需要关注,只需要关注输出的描述文件是否符合规范。
现在,我们将设计并实现一个物料平台,使其与渲染器完全解耦,专注于输出符合规范的描述文件
首先我们需要有一个份协议方案,用于规范描述文件的内容,同样也是不同模块之间沟通桥梁,类似于AI中的MCP,万能接口。
物料设计原则
- 单一职责: 每个物料应该只做一件事
- 可组合性: 物料应该可以和其他物料组合使用
- 可配置性: 通过属性配置而非硬编码
- 自包含: 物料应该包含所有需要的资源
- 一致性: 遵循统一的设计语言和交互模式
物料平台可以独立拆分成一个独立项目,渲染器只要封装成一个组件就好了。
物料平台中的描述文件也可以保存到服务上数据库中,我们只需要把组件的文件放到项目中特定的位置,在物料平台中进行配置,可能是可视化的配置,或者交给AI对话的形式,生成JSON类型的描述文件保存到数据库中。可以支持文件上传等方式,我们把组件文件上传,然后在物料平台中进行配置。
物料平台设计
用户 --> 组件上传 --> 组件分析
|
v
AI处理 --> 描述生成
|
v
人工审核 --> 数据库存储
|
v
低代码平台 <-- API服务 <-- 物料加载服务
协议设计
/**
* 优化的物料描述类型定义
* 扁平化结构、清晰分离关注点、增强可扩展性
*/
import type { Component } from 'vue';
/**
* 物料基础信息
*/
export interface MaterialBase {
// 标识信息
id: string; // 唯一标识符
type: string; // 组件类型标识,用于渲染引擎匹配
version: string; // 物料版本
// 显示信息
name: string; // 组件显示名称
description?: string; // 组件描述
icon?: string; // 组件图标
group: string; // 组件分组
order?: number; // 显示顺序
// 标签
tags?: string[]; // 标签(用于搜索和过滤)
}
/**
* 物料来源配置
*/
export interface MaterialSource {
// 来源类型: 'builtin' | 'local' | 'remote'
type: string;
// 内置组件时的组件引用
component?: Component;
// 本地组件时的导入配置
import?: {
path: string; // 导入路径
name?: string; // 导出名称
destructuring?: boolean; // 是否需要解构导入
};
// 远程组件时的配置
remote?: {
url: string; // 远程地址
version?: string; // 版本要求
};
}
/**
* 属性定义(使用JSON Schema)
*/
export interface PropDefinition {
type: string; // 类型
title?: string; // 标题
description?: string; // 描述
default?: any; // 默认值
required?: boolean; // 是否必须
// 针对不同类型的扩展属性
enum?: any[]; // 枚举选项
items?: PropDefinition; // 数组项定义
properties?: Record<string, PropDefinition>; // 对象属性定义
// UI相关配置
ui?: {
component?: string; // 用于编辑的组件
hidden?: boolean; // 是否在属性面板隐藏
group?: string; // 属性分组
order?: number; // 显示顺序
[key: string]: any; // 其他UI配置
};
}
/**
* 事件定义
*/
export interface EventDefinition {
name: string; // 事件名称
description?: string; // 事件描述
params?: PropDefinition[]; // 参数定义
}
/**
* 插槽定义
*/
export interface SlotDefinition {
name: string; // 插槽名称
description?: string; // 插槽描述
allowedTypes?: string[]; // 允许放置的组件类型
maxItems?: number; // 最大允许放置数量
}
/**
* 样式定义
*/
export interface StyleDefinition {
default?: Record<string, any>; // 默认样式
variants?: Record<string, Record<string, any>>; // 样式变体
states?: Record<string, Record<string, any>>; // 状态样式(如hover)
}
/**
* 约束条件
*/
export interface Constraints {
parent?: string[]; // 允许的父组件类型
children?: string[]; // 允许的子组件类型
position?: {
absolute?: boolean; // 是否允许绝对定位
fixed?: boolean; // 是否允许固定定位
};
customRules?: string[]; // 自定义约束规则
}
/**
* 物料扩展配置(使用命名空间)
*/
export interface Extensions {
[namespace: string]: any;
}
/**
* 运行时配置
*/
export interface RuntimeConfig {
draggable?: boolean; // 是否可拖拽
resizable?: boolean; // 是否可调整大小
droppable?: boolean; // 是否可放置其他组件
selectable?: boolean; // 是否可选中
removable?: boolean; // 是否可删除
editable?: boolean; // 是否可编辑
}
/**
* 完整的物料描述接口
*/
export interface MaterialDescriptor extends MaterialBase {
source: MaterialSource; // 物料来源
props: Record<string, PropDefinition>; // 属性定义
events?: EventDefinition[]; // 事件定义
slots?: SlotDefinition[]; // 插槽定义
style?: StyleDefinition; // 样式定义
constraints?: Constraints; // 约束条件
runtime?: RuntimeConfig; // 运行时配置
extensions?: Extensions; // 扩展配置
// 物料实例化时的默认配置
defaultConfig?: {
props?: Record<string, any>; // 默认属性值
style?: Record<string, any>; // 默认样式
children?: any[]; // 默认子元素
};
}
/**
* 物料注册信息
*/
export interface MaterialRegistration {
descriptor: MaterialDescriptor;
component?: Component | null;
asyncLoader?: () => Promise<Component>;
}
// 移除默认导出,仅使用命名导出
// export default MaterialDescriptor;
协议规范了渲染器,物料平台保证所以进入的组件最终输出都是根据协议生成的规范描述文件,渲染器就可以正常的渲染出来。
物料平台设计
物料平台负责维护低代码中可以使用的组件库,包括上传下载编辑预览和AI识别等功能
上传的组件库文件通过AI依据协议文件整理一遍输出符合规范的描述文件,存入数据库中,低代码平台可以通过接口获取。
新建物料
新增物料分三步 1.组件的基础内容 2.编辑或上传组件 3.AI转描述文件