起源
年前接手一个项目使用时需要动态设计表单,那么显然需要一个表单设计器,公司主要使用框架是vue所以能找到的表单设计器就有:avue、formMaking、variantfrom ...等,又因为需求中需要组件联动如: 组件之间控制展示隐藏、Select等组件源动态加载不同的远程数据、还需要组件可以自由扩展...显然前边几个设计器都不符合要求,自己动手撸一个又太花时间成本又不允许,领导拍板改avue源码做一个。
吐槽一下,说实话avue的源码一言难尽 几乎没有设计可言
经历
从此痛苦开始了...
- 修改嵌套树结构 (组件递归节点过多易卡死.)
- 控制组件需提升数据至父组件(组件被控制会导致函数多次重复计算)
- 被控制组件的数据是否仍需保留
- 自定义组件添加
- 最后保存的组件json结构臃肿,内置大量需执行字符串函数、bug排查困难
- ....
经过一番痛苦折磨后最终完成并上线了,但是效果并不好用起来不流畅,且维护困难。
思考
查过很多表单设计器源码后发现都是大差不差的内容,为什么表单设计器都这么难用?难以维护的痛点都在控制逻辑代码与显示代码数据转换代码都混在一起,可不可以清晰一点。并且打包体积很大表单设计器修改一次整个前端项目都需要发版,想到可以用微前端方法拆分出来,就在这个时候也突然想到了formily
微前端
独立开发、独立部署微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新。
formily
一个古老的表单json表单方案,formily可以轻松做到组件之间联动、嵌套、布局等问题仅需一个json结构、缺点是formily的上手需要一点点的学习成本,并且formily有内置的表单设计器!!简直吕布见到貂蝉的感觉,这不就是我想要的。
设计器单独部署解决维护设计器时项目需要一起发版问题,并且微前端方案完美解决vue项目与react项目同时使用
formily设计器扩展
formily扩展自定义组件还是比较容易的,但是设计器代码里添加自定义的组件找了很久官方也没有文档、资料也比较难查最后经过翻查源码还是被我解决了。哈哈哈!
补刀,formily设计器的源码设计就挺强的~
formily设计器添加自定义组件
官方地址 源码自行下载 formilyjs.org/zh-CN/guide...
建议:自己搭建一个react项目只安装设计器就可以了 怎么搭建react项目我就不贴出来了,我这里是用vite + react18创建一个空项目
安装设计器
npm install --save @designable/formily-antd
这里会有小伙伴安装后出现跑不起来的情况,建议照着官方示例源码把需要的文件全部复制过来,如果出现less问题就安装less,或者还会有文件地址找不到的情况,我这里用的是vite所以修改一下vite的文件路径别名对应一下就可以了,如果有其他问题可以给我留言
- 创建自定义组件
根路径创建 custom-compoent文件夹放置自定义的组件
组件内容很简单
js
// props中将来会传进来 value disabled readonly onChange方法等内置属性用来控制组件
// change(xxxx) 执行change方法就可以变更value值,value默认会是undefined
// 需要在设计器右侧属性控制栏添加的属性也会在props中传进来
export const Uploda = (props:any)=> {
console.log(props)
return <Button>
UploadShowTable
</Button>
}
我这里的外层index仅仅是做了统一导出
js
export * from './UploadShowTable'
2.添加组件行为属性 components中新增自定义的组件并添加属性,照着其他组件抄就可以仅需把导出的名称做个修改 也跟也一样prview导出index导出等统一一下
js
// designerLocales 国际化语言这里可以直接中文或者也可以照着其他组件一样ctrl c v 改ok了
// designerProps 组件的属性控制源
import React from "react";
import { UploadShowTable as FormilyUploadShowTable } from '@/componentCustom'
import { createBehavior, createResource,GlobalRegistry } from "@designable/core";
import { DnFC } from "@designable/react";
import { createFieldSchema } from "../Field";
import { AllSchemas } from "@/core/schemas";
import { AllLocales } from "@/core/locales";
export const UploadShowTable: DnFC<React.ComponentProps<typeof FormilyUploadShowTable>> = FormilyUploadShowTable;
UploadShowTable.Behavior = createBehavior(
{
name: "UploadShowTable",
extends: ["Field"],
selector: (node) => node.props["x-component"] === "UploadShowTable",
designerProps: {
propsSchema: createFieldSchema(AllSchemas.UploadShowTable),
},
designerLocales: AllLocales.UploadShowTable,
}
);
UploadShowTable.Resource = createResource(
{
icon: "UploadSource",
elements: [
{
componentName: "Field",
props: {
type: "Array<object>",
title: "UploadShowTable",
"x-decorator": "FormItem",
"x-component": "UploadShowTable",
"x-component-props": {
textContent: "UploadShowTable",
},
},
},
],
}
);
3.添加国际化
locales下文件夹一样照样画葫芦CV一个并且修改title,依次都导出即可。
4.自定义组件的控制属性 core/schemas 这里配置的内容就是属性栏的属性,结构就和schema表单一模一样,直接写就行了。 记得也一样都导出
js
import { ISchema } from '@formily/react'
export const UploadShowTable: ISchema = {
type: 'object',
properties: {
textContent: {
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
},
action: {
'x-decorator': 'FormItem',
'x-component': 'ValueInput',
'x-component-props': {
include: ['TEXT', 'EXPRESSION'],
},
},
name: {
type: 'string',
'x-decorator': 'FormItem',
'x-component': 'Input',
'x-component-props': {
defaultValue: 'file',
},
},
....
}
}
- 注册自定义的组件
设计器的主页面 ResourceWidget 和 ComponentTreeWidget 组件中添加自定义的行为方法
js
....
Space,
FormTab,
FormCollapse,
FormLayout,
FormGrid,
+ UploadShowTable,
} from "@/components";
...
...
<ComponentTreeWidget
components={{
Form,
+ UploadShowTable
...
...
<ResourceWidget
title="sources.Inputs"
className="bg-white"
sources={[
Input,
+ UploadShowTable
...
...
最后 MarkupSchemaWidget、PreviewWidget 中都注册自定义的组件
js
...
+ import { UploadShowTable } from '@/componentCustom'
...
const SchemaField = createSchemaField({
components: {
Space,
FormGrid,
+UploadShowTable
...
大功告成!