vue3 + ts
协议是低代码的基石
1、协议
协议(其实就是约束),它主要包括物料创建协议、物料属性协议、动作协议、动画协议等等。这个东西贯穿低代码的整条链路。一个json驱动组件渲染,组件维护、新增、解析等都需要围绕这个json:
- 相应的协议扩展物料
- 把左侧一个物料拖到中间画布区通过协议来通信和解析
- 选中画布区域的组件时,通过右边设置面板进行属性设置时,也需要通过协议来通信和解析
- ...
2、物料区 (我这里使用的npm包,将物料区作为一个组件库发布至npm)
左侧的物料区,这是开始
以下是物料创建的协议(约定)
/**
* @description 单个组件注册规则
*/
export type VisualEditorComponent = {
maximum: number;
/** 组件name */
key: string;
/** 组件所属模块名称 */
moduleName: keyof ComponentModules;
/** 组件唯一id */
_vid?: string;
/** 组件中文名称 */
label: string;
/** 组件预览函数 */
preview: () => JSX.Element;
/** 组件渲染函数 */
render: (
data: {
props: any;
model: any;
styles: CSSProperties;
block: VisualEditorBlockData;
custom: Record<string, any>;
formVid?: string;
},
context?: any,
) => () => JSX.Element;
/** 组件是否可以被拖拽 */
draggable?: boolean;
/** 是否显示组件的样式配置项 */
showStyleConfig?: boolean;
/** 组件属性 */
props?: Record<string, VisualEditorProps>;
/** 动画集 */
animations?: Animation[];
/** 组件事件集合 */
events?: { label: string; value: string }[] | string[];
/** 组件样式 */
styles?: CSSProperties;
};
以下是物料属性的协议
export enum VisualEditorPropsType {
/** 输入框 */
input = 'input',
/** 数字输入框 */
inputNumber = 'InputNumber',
/** 颜色选择器 */
color = 'color',
/** 下拉选择器 */
select = 'select',
/** 单选组 */
radioGroup = 'radioGroup',
/** 表格 */
table = 'table',
/** 开关 */
switch = 'switch',
/** 可拖拽项 */
crossSortable = 'CrossSortable',
/** Upload 上传 */
upload = 'Upload',
}
物料区本身很简单:
-
组件的分类:
- 容器组件(这类组件主要用来协助布局和嵌套)
- 基本组件(常见的有图片、文本、输入框、视频等)
- 集成度稍高一点的组件(表格、表单、图表、自定义组件、业务组件)
-
如何渲染组件:
- vue3+JSX defineComponent 创建组件 setup 返回jsx
name: 'CompRender',
props: {
element: {
type: Object as PropType<VisualEditorBlockData>,
default: () => ({}),
},
},
setup(props) {
return componentMap[props.element.componentKey].render({
styles: props.element.styles || {},
props: props.element.props || {},
model: {},
block: props.element,
custom: {},
});
},
});
3、画布区(渲染器)
- 流式布局:组件从左到右从上往下自然排列,就是单纯的从上往下平铺开来(一般用做移动端项目)
- 栅格画布:类似前端组件库中的栅格布局,一行 24 列,一行 12 列这样划分填充,看起来比较规范也比较整齐(一般用做PC端管理后端)
4、属性编辑区(设置器)
这个区域通常会支持三种基本的设置:props && 样式 && 事件。一般来说我们的操作是这样的:
- 点选画布区的某个组件
- 触发设置某个全局变量为当前组件 currentBlock (组件属性)
- 右侧属性面板就会根据 currentBlock(组件属性),这个 currentBlock 其实就是一开始在物料协议里面约定的 props,但是和 props 可能有点小区别,需要自己手动写个函数转一下;
- 用户自定义的交互,参考物料属性的约定,自定义约束类型。
其他问题
模块之间如何进行解耦呢:
- 通过全局数据来共享,而不是通过直接相互传递数据(vuex、provide&inject 等)
- 独立项目,开发起来自然就会强迫自己解耦了
- 好处:重构或者替换某一个模块时,可以直接替换单个模块而不影响其他地方的逻辑
如何做版本控制:
-
前端控制:
- NPM包本身就是增量发布,版本号对应
- CMS应该一直保持最新版本,无需做版本控制
- H5可以根据版本号将静态资源打包至对应版本目录,生成对应版本的H5路由,通过访问对应路由的静态文件来实现
总结
- 低代码重要的是方向(应当是单纯的、纯粹的)
- 低代码基石是:协议(约定)
- 低代码所有的操作都是在操作一个 json(组件属性props、组件动作events、组件动画animations等等)