上一篇文章已经介绍了如何实现自定义物料,详见 🛬🛬🛬手把手带你集成阿里低代码引擎vue物料库
本篇文章是低代码平台的应用篇,主要从渲染原理、架构、基本功能角度介绍,不涉及出码
1. 渲染原理
预览模式渲染原理
React
class Demo extends React.PureComponent{
static displayName = "renderer-demo";
render(){
return (
<div className="demo">
<ReactRenderer
key={schema.fileName
schema={schema}
components={components}>
</ReactRenderer>
</div>
)
}
}
预览模式通过schema 和components完成页面渲染
1.1 schema
搭建基础协议数据,渲染模块将基于 schema 中的内容进行实时渲染。
字段 | 含义 |
---|---|
componentName | 组件名,最外层渲染的是Page组件,使用PageRenderer类渲染 |
id | 节点的唯一标识 |
props | Page组件的属性,其中style为定义的行内样式 |
docId | 文档id |
fileName | 文件名 |
state | 等价于vue data里定义的数据 |
dataSourcce | 数据源,用于接口请求 |
css | 内联样式,可以在源码面板的css部分查看 |
lifecycles | 生命周期函数,对应不同渲染器的生命周期,非React框架需要做一对一映射 |
methods | 自定义方法 |
originCode | 源代码,会转为react的形式 |
hidden | 当前页面是否隐藏 |
isLocked | 当前组件是否被锁定 |
meta | 对应源码面板里的js代码 |
children | 当前节点的子节点,由此构成组件的嵌套关系,反映当前页面结构 |
1.2 components
渲染模块渲染页面需要用到的组件依赖的实例,components 对象中的 Key 需要和搭建 schema 中的componentName 字段对应。
注意,schema里使用的组件必须在components中进行声明,否则会无法渲染
componentsMap
它描述的是页面用到的组件的信息,例如从 ProCode 转化为我们的 json 协议内容如图:
javascript
import { AButton } from "lowcode-material-ant-vue";

其中destructuring 为 true 表示我们用解构的方式来获取组件,通过componentsMap中的描述,我们可知,AButton组件是在lowcode-material-ant-vue库中
1.3 渲染能力概览

我们要渲染的页面,可以把它解析为一个树状结构 ,其中最底层的节点就是最小粒度的组件
组件需要支持的能力:
- 获取源码组件
- 解析组件的props
- 获取组件的children
- 保留传入上下文,包括插槽上下文、循环上下文等
- 节点更新,当参数变化时更新对应节点
- 节点循环处理
- 获取节点实例并存储
- 节点的事件处理
比组件维度更大的是页面,它需要支持的能力有:
- 页面生命周期初始化和执行
- 页面组件树的描述生成,并递归处理单个组件
- 页面上下文生成,比如数据源state、低代码组件的props等
- 页面API支持等
2. 渲染框架原理
2.1 整体架构
协议层:schema
能力层: 提供组件、页面、区块需要渲染的核心能力,包括props解析、样式注入、条件渲染、循环渲染等
react框架对应 react-renderer
vue框架对应 vue-renderer
适配层:由于我们使用的运行时框架不是统一的,所以统一使用适配层将不同运行框架的差异部分,通过接口对外,让渲染层注册/适配对应所需的方法。能保障渲染层和能力层直接通过适配层连接起来,能起到独立可扩展的作用
对应代码在packages/renderer-core/src/adapter/index.ts中实现
渲染层:提供核心渲染方法,不同框架实现不一,需要通过适配层进行注入
应用层:应用到具体项目
2.2 lowcode-engine-vue实现
通过schema描述的json定义,创建对应的vue组件,组件的嵌套关系通过schema.children实现,核心功能
低代码渲染能力,通过vue-renderer和vue-simulator-renderer包实现的,底层是基于renderer-core实现的
vue-renderer实现
vue-renderer代码示例
xml
<template>
<div class="lowcode-plugin-sample-preview">
<Suspense>
<VueRenderer
class="lowcode-plugin-sample-preview-content"
:schema="schema"
:components="components">
</VueRenderer>
</Suspense>
</div>
</template>
<script>
import VueRenderer from "@knxcloud/lowcode-vue-renderer";
import { toRaw,Suspense } from "vue";
import { AButton } from "lowcode-material-ant-vue"
export default(){
components:{
VueRenderer,
Suspense,
AButton
},
data(){
return {
schema:"",
components:{
AButton
}
}
},
mounted(){
this.init();
},
methods:{
init(){
this.schema = {
componentName: 'Page',
props: {},
children: [
{
componentName: 'AButton',
props: {
type: 'primary',
style: {
color: '#2077ff'
},
},
children: '确定'
}
}
}
}
}
</script>
VueRenderer执行过程
接收props作为参数,类型定义如下

在vue组件的setup阶段,执行渲染相关的方法
页面初始化
获取vue实例,分别初始化emit、beforeCreate、initProps、props、setup、inject、methods、state、computed、watch、provide、处理生命周期、css、国际化、created
生命周期处理
从schema的lifecycles字段拿到所有页面定义的生命周期,符合上述的定义,则执行对应的生命周期方法
数据更新
computed监听props.schema属性,发生变更则执行updateSchema方法,根据当前节点的类型判断使用哪种更新,节点是插槽,执行全量更新 ;节点是其他类型,执行增量更新;
2.3 vue-simulator-renderer实现
相对于vue-renderer,vue-simulator-renderer外层包裹了一层Suspense组件,渲染核心实现与上一小节相同
由于是在画布渲染,还支持了节点拖拽、锁定等功能;通过vue-router增加了路由支持;
节点处理
支持注释、文本、空节点、DOM节点等类型的处理
位置信息
通过node.getBoundingClientRect()获取,通过selectstart、dragstart等事件监听支持拖拽
内置组件
实现了Leaf、Slot、Page内置组件
3.集成方案
3.1 总体架构设计

实现方案
- 低代码服务,主要用于保存各个schema描述文件,支持路由跳转、新建路由功能。每个page页面对应一个schema
低代码插件,插件化架构,符合主体项目架构的高内聚、低耦合、插件化管理原则。
使用vue实现渲染组件: 低代码插件的实现需要对低代码页面搭建协议规范的schema.json渲染出真正的页面组件,在缺少vue2版本的vue-renderer渲染组件前提下,考虑到今后项目中要对vue版本升级,所以采用社区已经实现vue3版本的vue-renderer,可以更快的投入开发
兼容vue2项目 :部门各个业务项目基本都是vue2实现,vue-renderer是vue3实现,需要达到两者兼容,目前有微前端、iframe、模块联邦等方案;经过对所有方案的代码实践,微前端的主应用和微应用通讯封装完整,交互容易,内存变量共享,url同步,低耦合等优点,最终选择微前端方案作为解决vue版本兼容的问题,而微前端方案中,qiankun具有社区使用最多,社区活跃,对现有项目改动很少等优点(更多微前端解释参考总结说明)
- 低代码插件实现
低代码插件的主要功能将低代码服务中该主应用下的路由信息和schema.json数据通过ajax请求下来,通过在插件中路由解析方法和vue-renderer解析schema.json文件,最终生成一个带有路由系统的插件应用。
定义插件生命周期函数: 在插件的入口文件内,定义 mount、bootstrap、unmount等作为插件的生命周期函数,这样主应用中注册插件时,自动执行生命周期函数启动插件
生成路由: 提前在vue-renderer基础上封装一个通用的组件,该组件接收一个存放schema文件的路径props,通过props中的schema的路径,采用Ajax获取该路径下schema.json文件,将获取到的信息传递给vue-renderer组件,最终将数据解析为页面组件,生成页面,递归遍历请求来的路由信息,为每个路由下挂载封装好的通用组件,并定义该组件的schema路径props,这样在切换路由就可以改变props,就可以达到切换不同页面的效果了
- 主应用注册 低代码 插件
主应用中,主要在UI插件中通过qiankun注册低代码插件,注册后通过路由的变化,来切换微应用中路由变化
主应用注册 低代码 插件: qinakun提供了registerMicroApps和loadMicroApp 方法来注册插件,两者的区别一个是主动注册,一个是手动注册,在考虑到有可能不会进入插件应用页面内,为了节约性能开销,可以通过loadMicroApp 手动注册插件,插件应用需要配置应用的名称name,应用的主入口entry,应用的路由匹配规则activeRule,还可以通过配置props参数给插件应用传递参数,loadMicroApp还可以给插件应用配置一些其他参数,具体可参考qiankun的loadMicroApp 的api使用
低代码页面使用: 在需要的模块下添加路由,设置与低代码插件中已有的路由路径,这样在主应用路由变化后,在匹配到activeRule规则后,将从插件应用中匹配路由路径,从而加载对应低代码页面
3.2 方案说明
3.2.1 低代码平台层
在低代码平台层中在应用列表中选中要编辑的应用,进入编辑器页面中进行编辑该应用的路由配置信息和页面schema信息,编辑后点击保存通过调用接口存入服务层对应的低代码应用中,也可以进行预览当前编辑的页面

应用页初始化
应用列表的数据来自服务层的低代码应用数据,如果初始化为空数据时,可以点击新建应用,填写应用信息后,将通过接口把数据存入服务层中。在该页面下实现新增应用、删除应用、点击跳转编辑器功能


编辑器搭建
采用低代码引擎的插件系统、画布面板、属性设置器,快速搭建符合要求的低代码编辑器。
物料的的生成:基于社区的Vue3实现的ant-design-vue UI组件库,按照低代码物料生成协议要求,书写每个UI组件的物料描述文件,最终生成打包生成一个总的物料资产信息json文件,通过调用编辑器API将资产信息转化为一个个物料组件展示在物料插件面板中
路由的新增和修改: 打开路由管理插件面板,将初始化请求低代码服务中对应应用下的路由配置信息,展示在面板中,在选中一个路由后,将通过路由Path请求对应页面schema.json信息,调用编辑器API将页面schema信息解析在画布面板进行渲染,渲染后就可以进行编辑修改了。
还可以通过右键选择创建新的路由,填好对应的路由信息,点击创建后,调用编辑器API生成一个只有根Page组件的画布面板,这时就可以拖入物料进行排版布局生成完整的业务页面了

接口创建与调用: 打开dataSource插件面板中,可以新建或修改不同类型(fetch、jsonp、mopen、mtop)的请求方式的接口,选中新建类型后,将会弹出配置网络请求的常用配置项面板,其中数据源ID将会作为该接口的唯一id,然后就可以在源码面板中通过this.dataSourceMap.数据源ID.load()调用此接口。所有的新增或修改的接口信息,通过编辑器API转化,最终保存在页面schema.json文件的dataSource字段中
其他编辑功能:所有的编辑功能最终的目的就是生成符合 低代码 页面搭建协议的页面schema信息,实现符合业务需求的页面
- js源码面板中可以使用vue3语法编写页面源码,包括业务逻辑方法、生命周期、初始化state信息等,最终展现在schema对应的字段中(methods、lifeCycles、state等),编辑后点击保存将在画布中实时生效

3.2.2 低代码服务层
低代码服务采用Node.js作为后台服务,在整个架构中起到承上启下作用,主要功能保存着低代码应用列表信息,每个应用信息中又包含应用下路由配置信息和页面schema文件,通过RESTful api风格封装接口提供给平台层和应用层使用,接口服务包含应用的新增与删除 ,应用中路由配置信息和页面schema信息的增删改查功能
3.2.3 低代码应用层
在应用层中,开发者可以通过实现低代码插件方式使用服务层中低代码应用下的路由配置信息和页面schema信息,生成路由页面后,通过主应用UI插件注册低代码插件后,使用低代码插件功能 低代码插件(ui-plugin-oss-lowcode为例)的主要功能将低代码服务中该主应用下的路由信息和schema.json数据通过ajax请求下来,通过在插件中路由解析方法和vue-renderer解析schema.json文件,最终生成一个带有路由系统的插件应用。
定义插件生命周期函数: 微应用需要在入口文件,定义 boostrap、mount、unmount等作为插件的生命周期函数,以供主应用在合适的时机调用
配置微应用的打包工具:除了代码中暴露出相应的生命周期钩子之外,为了让主应用能正确识别微应用暴露出来的一些信息,微应用的打包工具需要增加如下配置:
ini
const name = require('./package.json').name;
module.exports = {
output: {
library: name,
libraryTarget: 'umd',
chunkLoadingGlobal:`webpackJsonp_${name}`,
},
};
生成路由: 提前在vue-renderer基础上封装一个通用的组件,该组件接收一个存放schema文件的路径props,通过props中的schema的路径,采用Ajax获取该路径下schema.json文件,将获取到的信息传递给vue-renderer组件,最终将数据解析为页面组件,生成页面,递归遍历请求来的路由信息,为每个路由下挂载封装好的通用组件,并定义该组件的schema路径props,这样在切换路由就可以改变props,就可以达到切换不同页面的效果了
- 主应用注册 低代码 插件
在壳子应用(ui-shell)和主应用(ui-plugin-oss)分别引入qiankun
- 壳子应用的registerPlugins.js增加qiankun的注册逻辑
scss
// registerPlugins.js
...
export function applyUiPlugins(routerOptions,store,Vue,apis,config){
...
if(pIns.registerQiankun){
pIns.registerQiankun(store)
}
}
- 壳子应用的Content.vue中启动qiankun
javascript
import {start} from "qiankun"
mounted(){
if(!window.isQiankunStart){
start({
sandbox:{experimentalStyleIsloation:true}
})
window.isQiankunStart = true
}
}
- 主应用插件在入口文件通过qiankun注册低代码插件,注册后通过路由的变化,来切换微应用中路由变化
php
registerMicroApps([
{
name: '微应用的唯一标识名', // app name registered
entry: '//localhost:{应用端口号}/',
container: '#lowcode-wrapper',
activeRule: '/#/lowcode',
}
]);
主应用注册 低代码 插件: 插件应用需要配置应用的名称name,应用的主入口entry,应用容器id,应用的路由匹配规则activeRule
低代码 页面使用: 在需要的模块下添加路由,设置与低代码插件中已有的路由路径,这样在主应用路由变化后,在匹配到activeRule规则后,将从插件应用中匹配路由路径,从而加载对应低代码页面