格子表单/GRID-FORM已在Github 开源,如能帮到您麻烦给个星🤝
点此查看👉在线文档及演示 👈
GRID-FORM 系列文章
- 基于 VUE3 可视化低代码表单设计器
- 嵌套表单与自定义脚本交互
新版本功能 🎉
不觉间,
GRID-FORM
已经开源一年(2023年1月29日首次提交),初始版本功能较为简单,能用但很死板。后来陆续进行小版本迭代,增加诸如
数据联动
、
右键菜单
等,可是作为常用且必要的
嵌套(子表单)
、
按钮
功能一直没有实现。于是就有了今年的第一个0.1.1版本:
- 支持
嵌套容器(子表单)
- 支持自定义
脚本交互
- 新增 Element Plus 渲染器,完善 Vant4 渲染器
- 新增组件:按钮、图片、静态表格
目前具备的模块与组件如下图(带边框为新增功能)所示:
运行时截图
表单渲染效果
从左到右分别是 NaiveUI、ElementPlus、Vant4对于同一表单的渲染效果
可视化设计器
子表单(嵌套)
所谓子表单,可以理解为大背包里面的小包,底下可以添加子字段,同时支持录入多条数据;常见应用于录入字段格式固定、条数不定的数据清单。
按照 GRID-FORM 的设计,初始表单为一个顶层容器,能够定义标签样式(如位置、对齐方式)、格子列数、尺寸大小等布局属性,还可以嵌套子容器(如上图中的
外层容器
、
子容器1
、
子容器2
),每个容器均能定义其布局属性,理论上支持无限嵌套(递归渲染)。
嵌套类型
子表单能够设置如下类型:
类型说明仅布局只作为布局上的分组,字段均为同级单个嵌入一个对象到父字段多行嵌入多个格式固定的对象(数组)到父字段
下面我用一个实际例子说明,比如要录入一则学生信息,字段包含:
字段名说明姓名、年龄、籍贯
仅布局
三个同级基本信息专业信息
单个
数据:名称、学院、学年教育经历
多行
数据:开始日期、结束日期、学校
最终得到的表单数据:
{姓名:"张三",年龄:19,籍贯:"广西",专业:{名称:"水利水电工程",学院:"土木建筑工程学院",学年:4},教育经历:[{开始日期:"2011.09",结束日期:"2020.06",学校:"XX市第一小学"},{开始日期:"2020.09",结束日期:"2023.06",学校:"XX市第一高级中学"}]}
效果演示
核心代码
<template><templatev-if="isMultiple"><tableclass="gf-render-table"><trv-for="(rowData, rowIndex) in formData":class="{striped:rowIndex%2==1}"><tdwidth="40"class="c"><n-popconfirm:negative-text="null"@positive-click="formData.splice(rowIndex, 1)"><template#trigger><n-buttonsize="small"type="primary"tertiarycircle>{{rowIndex+1}}</n-button></template>
删除第{{rowIndex+1}}行数据?
</n-popconfirm></td><td><n-grid:x-gap="gridGap":y-gap="gridGap":cols="form.grid":style="{width: form.width, margin:'0px auto' }"><templatev-for="(item, index) in form.items":key="index"><n-form-item-giv-if="item._hide!=true":span="item._col":show-feedback="false":show-label="!(item._hideLabel === true || !form.labelShow)":label-placement="form.labelPlacement":label-align="form.labelAlign":label-width="form.labelWidth"><template#label>
{{item._text}}<spanv-if="item._required"style="color: red;"> *</span></template><componentv-if="item._container && item.items":is="buildComponent(item, renders, false)"><render-container:gridGap="gridGap":renders="renders":form="item":formData="childForm(item)":labelPlacement="item.labelPlacement":labelAlign="item.labelAlign"/></component><componentv-else-if="item._widget=='DATE'"v-model:formatted-value="rowData[item._uuid]":is="buildComponent(item, renders, false)"/><componentv-elsev-model:value="rowData[item._uuid]":is="buildComponent(item, renders, false)"/></n-form-item-gi></template></n-grid></td></tr></table><divstyle="margin-top: 10px;text-align: center;"><n-buttonsize="small":disabled="!canAdd"[email protected]="onAddRow">+</n-button></div></template><templatev-else><n-grid:x-gap="gridGap":y-gap="gridGap":cols="form.grid":style="{width: form.width, margin:'0px auto' }"><templatev-for="(item, index) in form.items":key="index"><n-form-item-giv-if="item._hide!=true":span="item._col":show-feedback="false":show-label="!(item._hideLabel === true || !form.labelShow)":label-placement="form.labelPlacement":label-align="form.labelAlign":label-width="form.labelWidth"><template#label>
{{item._text}}<spanv-if="item._required"style="color: red;"> *</span></template><componentv-if="item._container && item.items":is="buildComponent(item, renders, false)"><render-container:gridGap="gridGap":renders="renders":form="item":formData="childForm(item)":labelPlacement="item.labelPlacement":labelAlign="item.labelAlign"/></component><componentv-else-if="item._widget=='DATE'"v-model:formatted-value="formData[item._uuid]":is="buildComponent(item, renders, false)"/><componentv-elsev-model:value="formData[item._uuid]":is="buildComponent(item, renders, false)"/></n-form-item-gi></template></n-grid></template></template><scriptsetup>import{ ref, computed }from'vue'import{ ContainerProps, ContainerMixin }from'@grid-form/common/render.mixin'import{ buildComponent }from'@grid-form/common'const props =defineProps(ContainerProps)const{ isMultiple, canAdd, childForm, onAddRow }=ContainerMixin(props)</script>
脚本交互
- 增加支持交互(单击、双击)的组件:按钮、图片
- 优化运行时函数:表单项数组对象增加
$
(致敬 JQuery😄)方法,便于快速按ID/编号
查找内容
//找到编号为 name 的表单项(返回首个匹配值),并禁用
items.$("name").disabled =true//找到编号为'name'、_text为'专业名称'的表单项(返回首个匹配值),并禁用
items.$({_uuid:"name","_text":"专业名称"}).disabled =true
结语
因个人能力有限,此工具在设计、实现上存在诸多不足,仅作学习交流🙂。
版权归原作者 集成显卡 所有, 如有侵权,请联系我们删除。