对于可视化的搭建表单,试卷等场景,让不懂技术的人也能拖拽式创建自己的表单和试卷。
图片
今天就来和大家分享一下橙子试卷的技术架构和技术实现, 如果你也在调研零代码, 低代码, 或者表单引擎等技术, 那么这篇文章也许可以给你带来一些灵感。
图片
体验地址: https://turntip.cn/form-engine
文末会附技术交流群, 感兴趣的朋友可以加入交流讨论。
之前在开发 H5-dooring 零代码搭建平台时我采用的是React技术栈, 因为用 react 写复杂逻辑会更顺手, 好在 vue3 也支持了函数式的写法, 也提供了 hooks 机制, 让我们写逻辑驱动的应用更加方便, 所以橙子试卷采用了国内最流行的 vue3 作为前端框架。具体技术栈如下:
当然还有一些第三方组件这里就不一一介绍了。我们的核心在于从零完整设计一套 MVP 的零代码搭建引擎, 所以后端部分, 大家可以替换成自己熟悉的 Java, Go, Python 等语言。
图片
因为零代码表单引擎设计的核心是如何构造一套低成本且可扩展的组件库, 并快速应用到实际业务场景, 所以设计的核心就包括如下部分:
接下来我会详细介绍这几块的技术实现, 当然实现思想和技术栈无关, 我们仍然可以把它应用到不同的技术体系中。
图片
因为我们的搭建场景是问卷, 试卷, 微页面, 所以组件库会围绕表单来扩展, 比如常用的:
等等, 这些组件当然不能满足所有客户的业务场景, 所以我们要设计一种可扩展组件库, 并且开发成本较低的方案。
我们可以参考常见的低代码平台的设计思路:
图片
简言之就是把核心UI和逻辑作为组件的主文件, 同时暴露标准的可配置属性和可配置逻辑。
之所以强调“标准”, 是为了让不同组件能共用一套属性配置引擎, 从而让组件二开的成本大大降低(专注于组件的开发, 而不是配置的兼容)。
图片
其次为了尽可能让组件的配置更灵活, 我们需要提供一套标准的组件默认属性, 让用户可以根据默认属性来配置自己的个性化的样式, 那么我们的组件就需要这么来设计:
图片
这里以橙子试卷的文本组件给大家举个例子。
文本组件的主文件:
{{ editorStore.data[index].titleText }}
文本组件的可配置属性:
export default class Text {
component: TextPropType;
constructor(id: string) {
this.component = {
component: 'text',
type:'editor.text',
id,
check: true,
titleText: 'https://turntip.cn/form-engine',
titleColor: 'black',
titleSize:16,
titleWeight:'500',
padding: [0, 0, 0, 0],
margin: [10, 10, 10, 10],
animation:'',
direction: 'center',
link:'https://turntip.cn/formManager',
delay:2,
attrbite: [
{
name: 'editor.titleText',
field: 'titleText',
component: 'textarea'
},
{
name: 'editor.padding',
field: 'padding',
component: "padding",
props: {
min: 0,
type:'padding'
}
},
{
name: 'editor.margin',
field: 'margin',
component: "padding",
props: {
min: 0,
type:'margin'
}
},
]
}
}
}
通过这种方式, 我们只需要根据业务需求实现自己的组件, 编写组件可配置的属性json, 即可通过配置引擎来动态生成组件的可编辑面板, 从而让非技术人员轻松编辑组件:
通过以上的方式, 我们可以轻松开发各种自定义的组件, 提供给用户使用:
图片
图片
对于表单场景, 我们不需要特别复杂的布局交互, 所以这里我才用拖拽排序来实现页面的搭建, 同时支持组件快捷复制和删除。
目前 vue3 的比较成熟的拖拽组件有:
这里选择vuedraggable 来实现拖拽排序, 并对其进行上层封装, 实现体验更好的组件搭建排序效果。
当然还有很多优秀的拖拽库, 如果大家对vue3-draggable-resizable 感兴趣, 也可以试试, 它支持网格布局和自由布局, 可以实现更自由的布局搭建效果:
图片
在组件库设计中我们为了统一管理和维护组件和组件的属性配置, 需要定义统一化的 DSL 结构, 这个结构包含了组件的如下信息:
后4个都好理解, 这里介绍一下组件元数据, 它的价值在于定义组件的基本信息:
通过对 元信息 的定义, 我们可以很方便的建立更系统的组件库, 比如支持组件分类, 组件版本切换, 组件加载(通过路径元信息来加载远程组件)。
所以我们需要尽可能规范统一的定义组件的通用规则和自定义规范, 以便让不同组件都遵行统一的规则来实现零代码搭建引擎的设计。
这里还是以橙子试卷为例子, 来介绍一下我们统一的DSL:
图片
首先我们看看文本的元信息:
这是一个简单的元信息, 它可以帮我们快速识别组件, 并为画布提供组件更具体的渲染信息, 不同组件都通过统一的配置来定义, 可以让我们的渲染器更加高效的渲染组件, 并降低组件维护成本。
在介绍组件的内容中我已经介绍了组件接受的 json 配置结构, 这里分享一个由多个组件组成的完整页面的 DSL 结构和实际代码:
图片
案例代码:
有了以上的统一 DSL 结构, 我们就可以轻松通过 JSON 来渲染页面, 同时也有更多的想象空间, 比如:
一个可视化零代码解决方案一定包含完整的用户使用链路, 即从搭建到投放再到信息收集的完整分析链路。
图片
当然不同的公司业务分析需求不同, 所以需要支持纯粹的数据收集和流转, 以便供不同业务使用。
目前橙子试卷提供了一套完整的数据收集能力, 对于试卷场景, 也提供了自动打分机制, 可以一键分析数据情况:
图片
当然这都是可以基于自身规则自己二次开发的, 橙子试卷只是提供了一套案例参考。
体验地址: https://turntip.cn/form-engine