GRID-FORM 基于 VUE3 可视化低代码表单设计器

楔子

大概 4 年前,我做了一个简单的动态表单功能,开发人员通过 UI 界面配置表单(其实就是添加常用的控件,如文本框、下拉框等)就能向用户提供数据查询,反响不错,尤其是偏后端开发的小伙伴。

GRID-FORM 基于 VUE3 可视化低代码表单设计器_第1张图片

时至今日,上述功能存在以下问题:

  • 不够灵活,无法满足不同场景的定制化需求
  • 设计界面简陋,功能有限
  • 组件有限,不支持扩展
  • 不支持自定义代码(回调函数)

想要什么

  • 简单灵活易用(用户仅需要极低的学习成本)
  • 支持VUE3(团队前端技术栈以 vue 为主)
  • 可视化表单设计(所见即所得)
  • 支持移动端渲染(团队使用 Vant4,PC端渲染支持 Naive UI、Element Plus)
  • 支持回调函数(事件监听)
  • 数据联动(某个值变动后影响其他表单项)
  • 能够自定义组件(满足定制化需求)

开源产品调研

目前书面上已经有不少优秀开源的同类产品,这里列出可二次开发的, 同时具备表单渲染、表单设计的工具(截止至 2022年底)

方案 框架 UI库 备注
formilyjs React、Vue AntD、Element、Vant等主流 校验事件交互阿里巴巴开源的表单设计工具体系,能做到一份表单设计多端适配;但是对 vue3 支持不完备(设计器得自己做)
FormMaking VUE AntD、Element 校验事件交互操作良好,需要高级版本才支持 vue3
form-generator VUE Element 校验 操作良好,预览不友好(不够直接爽快),目前不支持vue3
form-create VUE iView、AntD、Element、Naive UI 校验操作良好,支持多个 UI 框架,对 vue 2/3 均支持,无设计器
VForm VUE Element 校验事件交互 操作良好,开源版不支持数据源子表单

再造个轮子吧

同类型的开源产品各有千秋,适合不同的应用场景,然而跟我想要的还不够契合。权衡后,还是觉得自己弄一个。技术选型为 vue3 + naive UI,使用 pnpm 进行包管理(monorepo结构)。

GRID-FORM 基于 VUE3 可视化低代码表单设计器_第2张图片
不同于同类型产品的组件拖拽,我采用栅栏布局来堆积组件(实现起来简单,省事,暂不支持容器嵌套、子表单),通过设置组件占据的格子数可以使其独占一行,故取名 GRID-FORM(栅栏表单),源码详见 Github。
GRID-FORM 基于 VUE3 可视化低代码表单设计器_第3张图片

表单设计器

得益于 VUE 的响应式,设计器所见即所得显得尤为丝滑,不然得自己手撸监听配置项变动事件及界面重绘。

编辑器分为左中右三个区域(这是业内约定俗成的标准设计),有别于兄弟产品,我把左区域用作表单整体的参数编辑。为方便用户自定义组件,设计器对外暴露组件库参数,并封装了常用的组件(诸如输入框、单选/多选框、日期选择)。

GRID-FORM 基于 VUE3 可视化低代码表单设计器_第4张图片
组件分为数据型(对应上图中的输入组件选择组件)及展示型(上图的展示组件)两类,后者不参与表单提交。

渲染器

组件渲染

每个组件有唯一编号,渲染函数为一个Object(key 即为组件编号),需要扩展组件时添加对应的渲染函数即可。渲染时属性分为基本信息(名称我用 _ 开头加以区分)及组件层面两类,分别对应了组件渲染函数的两个参数:attrsprops

渲染引擎处理完属性后,调用 Render 函数(不同 UI 库各自实现,使用者可根据业务需要自行覆写)得到组件实例。此处以文本输入框 INPUT为例:

import { h } from 'vue'
import { NInput } from 'naive-ui'

const RenderFuncs = {
	/**
     * @param {*} props 组件/控件属性
     * @param {*} attrs 基本信息
     * @returns 
     */
    "INPUT" : (props, attrs)=>{
        if(props.rows > 1)  props.type = "textarea"
        return h(NInput, props, buildSlotWithPrefixAndSuffix(props))
    }
}

GRID-FORM 基于 VUE3 可视化低代码表单设计器_第5张图片

默认值

表单项默认值可以填写常量或占位符(在初始化时被模板引擎赋值),占位符格式为${code},用户可自行扩展处理函数。

校验

此处校验分为非空内容格式两种

当表单项勾选是否必填,则在提交前渲染器会对该值进行非空检测;若设置了校验正则,则对非空值进行正则表达式校验。

事件&钩子函数

事件ID 名称 回调参数 说明
onLoad 加载完成 (form) 在表单初始化后触发
onSubmit 表单提交前 (form,items) 当用户点击提交按钮后触发
onChange 数据值变动 (form,agent,items) 详见下一节数据联动
afterSubmit 表单提交后 (form) 注意该事件需由使用方手动触发(因为渲染器无法感知表单是否已正确提交)

参数说明

ID 名称 类型 说明
form 表单数据 Object 当前全部表单项的数据对象(支持响应式)
items 表单项清单 Array 来自设计器导出的表单项数组(支持响应式)
agent 变动内容 Object 包含三个属性:key(表单项ID)、from(旧值)、to(新值)

数据联动

常规的做法是输入类表单项增加事件(如 onChange、onBlur、onFocus 等),但是这样操(实)作(现)繁(困)琐(难),我的做法只需要填写一处代码(直观简单)

要启用联动需要满足以下条件:

  1. 填写表单的onChange事件代码
  2. 至少一个表单项勾选了监听值变动

渲染器初始化后,会对勾选监听值变动的表单项开启监听(没错,是每个表单值有独立的监听)从而获取到新旧值。注意,若在回调函数中对form改动会重新触发onChange事件。

示例

/**
 * 通过修改 items 下元素的 disabled(为 true 时禁用表单项)、_hide(为 true 时隐藏)
 * 可实现表单项的禁用与隐藏
 */ 
if(agent.key=='nature'){
    if(agent.to=='个体工商户'){
        items.filter(v=>v._uuid=='scale')[0].disabled=true
        form.scale = 1
    }
    else{
        items.filter(v=>v._uuid=='scale')[0].disabled=false
    }
}

适配更多 UI 库

目前已实现 Naive UIVant4 的渲染器

我封装了渲染器的基础框架(组合式 API), 帮助使用者根据需要快速适配心仪的 UI 库。

结语

因个人能力有限,此工具在设计、实现上存在诸多不足,仅作学习交流。

你可能感兴趣的:(低代码,vue.js,表单设计器,可视化)