手把手带你开发一个低代码可视化平台(二)(低代码开发平台设计)
前文回顾
我开源的商城零代码可视化搭建平台Mall-Cook受到大家喜爱,使我深受鼓励。本着授人以鱼不如授人以渔思想,在项目新建shelf分支,带大家从零开发一个自己的可视化搭建平台。
上一节我们:
- 介绍了可视化搭建的架构
- 详细讲解了可视化搭建的核心 – 一套规范
- 开发了一个搭建面板,包括物料的嵌套,物料的工具容器等。
物料JSON构建属性面板流水线
构建逻辑
今天我们来开发通过物料JSON构建数据面板的逻辑
我们以图片物料的生成的过程为例(内容过多,请放大图片观看),物料JSON解析为两块:
- 物料属性描述,用于生成属性表单面板
- 物料初始数据,生成物料深拷贝初始数据,并传入对应属性表单,可通过表单修改数据
物料JSON
每个物料JSON都是物料的身份证,记载了物料的详细信息。我们解析其中数据使用在:
- 物料模板列表 (使用物料初始数据)
- 生成物料属性表单面板 (使用物料属性描述)
{ "name": "图片", // 物料名称 "icon": "icon-image", // 物料图标 "fields": { // 物料属性 "imagePath": { // imagePath 属性 "label": "图片上传", // label "type": "upload", // upload 类型 "value": "" // 值 }, "radius": { // radius 属性 "label": "图片圆角", // label "type": "number", // number 类型 "value": 0 // 值 } }}
其中属性type定义了属性的类型,同时也选择了操作此属性所用的操作组件,我现在定义的基础类型如下:
开发实现
大家清楚逻辑后我们开始开发,实际开发主要分为:
- 实现物料JSON注册方法开发(初始化所有物料的属性描述、初始数据)
- 开发物料属性面板解析器开发
- 实现上述基础类型操作组件开发
物料JSON注册
开发逻辑我们把每个物料的JSON放在自己的包下。然后我就可以根据这个规则,利用require.context遍历custom-components包下文件,找到所有component.json进行物料注册
物料JSON注册方法实现:
/* * 解析物料Schmea,注册各物料属性参数与初始值 */import Vue from 'vue'// 调用注册物料registerComponentsSchema()// 注册物料方法function registerComponentsSchema () { // 获取custom-components包下所有component.json const files = require.context('@/custom-components', true, /component.json$/) // 物料属性描述对象 (使用object类型方便调用) let fields = {} // 物料初始化数据集合 let initializing = [] // 遍历component.json注册物料 files.keys().forEach(key => { // 获取物料名 const [, name] = key.split('/') let config = { component: name, ...files(key) } // 添加物料属性描述 fields[name] = config.fields // 添加物料初始数据 initializing.push(initDefaulValue(config)) }) // Vue原型上绑定物料属性描述对象,方便调用 Vue.prototype.$fields = fields // Vue原型上绑定物料初始化数据集合,方便调用 Vue.prototype.$initializing = initializing}// 获取物料初始数据,默认过滤fields属性function initDefaulValue (config) { let { component, name, icon, fields } = config let temp = { component, name, icon } setDefaultValue(fields, temp) return temp}// 递归设置各层级初始数据(会存在多层级复杂对象类型)function setDefaultValue (fields, initializing) { for (let key in fields) { let { type, value, child } = fields[key] if (type == 'object') { initializing[key] = {} child && setDefaultValue(fields[key].child, initializing[key]) } else { initializing[key] = value } } return initializing}
通过注册我们会获得:
- Vue.prototype.$fields (物料属性描述对象)
- Vue.prototype.$initializing(物料初始化数据集合)
属性面板解析器
开发逻辑
- 遍历属性描述对象,获取每个属性的label、type等信息,然后渲染对应操作组件,生成属性表单。
- 传入物料数据,把value设到对应属性操作组件,即可通过操作属性表单进行修改
<template> <ul> <!-- 遍历物料属性描述对象 --> <li v-for="(s, key, index) in schema" :key="index"> <!-- 根据属性类型,渲染对应的操作组件 --> <component :key="index" :is="getComponents(s.type)" v-model="value[key]" v-bind="s" :schema="s" > <!-- 递归组件 --> <custom-schema-template v-if="s.child" :schema="s.child" :value="value[key]" ></custom-schema-template> </component> </li> </ul></template><script>export default { name: 'custom-schema-template', provide () { return { mode: this } }, props: { schema: { // 物料属性描述对象 typeof: Object, default: () => {} }, value: { // 物料数据 typeof: Object, default: () => {} } }, methods: { // 获取对应类型的操作组件名,组件名定义为:schema-类型 // 例: input类型 -> schema-input getComponents(type){ return `schema-${type}` } }}</script>
细心的同学会发现,属性面板解析器也是递归嵌套组件。这是因为属性类型除了基础类型外还存在复合类型,比如对象、对象数组等。复合类型会在下一节具体讲解。
基础类型操作组件
最后就是开发下图的基础类型操作组件,这块开发比较简单,我们任意举个栗子
sting类型 -> SchemaString组件
<template> <config-item :label='label'> <!-- input组件 --> <el-input v-model="mValue" v-bind="mOptions" :placeholder='mOptions.placeholder' size='small' ></el-input> </config-item></template><script>import schemaMixin from "@/mixin/schemaMixin";export default { name: "SchemaString", // 使用mixin,混入公用代码 mixins: [schemaMixin],};</script>
结尾
下一节预告
- 开发兼容物料属性复杂类型
- 开发JsonSchema生成器,可视化生成物料属性描述JSON