共计 5255 个字符,预计需要花费 14 分钟才能阅读完成。
上篇简要介绍了 formilyjs 以及基于其构建了表单设计器,实现了表单动静设计曾经预览性能,本片将介绍表单设计器的一些高级配置,使其能更好的使用于咱们的节点编辑以及连线编辑。
designable 高级配置
申请及自定义数据注入
一般来说,咱们页面的申请都是对立封装好的,在应用时咱们如何把咱们封装好的申请或者曾经有的数据源注入到咱们的
表单设计器中呢:
SchemaField 组件是专门用于解析 JSON-Schema 动静渲染表单的组件,在应用 createSchemaField
时咱们能够传入 scope
来注入到全局作用域中链接:
import {FC, Ref, useEffect, useImperativeHandle, useState} from 'react';
import {Modal} from 'antd';
import {
FormItem,
Input,
Form,
Submit,
ArrayBase,
ArrayCards,
ArrayCollapse,
ArrayItems,
ArrayTable,
ArrayTabs,
BaseItem,
Cascader,
Checkbox,
DatePicker,
Editable,
FormButtonGroup,
FormCollapse,
FormGrid,
FormTab,
GridColumn,
NumberPicker,
Password,
PreviewText,
Radio,
Reset,
Select,
SelectTable,
Space,
Switch,
TimePicker,
Transfer,
TreeSelect,
Upload,
} from '@formily/antd';
import api from '@/api';
import {createSchemaField} from '@formily/react';
import {LgetItem} from '@/utils/storage';
import {createForm} from '@formily/core';
interface PreviewProps {previewRef: Ref<{ setVisible: (flag: boolean) => void }>;
modalConfig: {[key: string]: any };
}
const SchemaField = createSchemaField({
components: {
Input,
ArrayBase,
ArrayCards,
ArrayCollapse,
ArrayItems,
ArrayTable,
ArrayTabs,
BaseItem,
Cascader,
Checkbox,
DatePicker,
Editable,
Form,
FormButtonGroup,
FormCollapse,
FormGrid,
FormItem,
FormTab,
GridColumn,
NumberPicker,
Password,
PreviewText,
Radio,
Reset,
Select,
SelectTable,
Space,
Submit,
Switch,
TimePicker,
Transfer,
TreeSelect,
Upload,
},
scope: {
$fetch: api,
selectList: [{label: 'aaa', value: 'aaa'}, {label: 'bbb', value: 'bbb'}]
}
});
const Preview: FC<PreviewProps> = ({previewRef, modalConfig}) => {const [visible, setVisible] = useState(false);
useImperativeHandle(previewRef, () => ({setVisible,}));
const [params, setParams] = useState({});
const normalForm = createForm({});
useEffect(() => {if (modalConfig && visible) {const playgroundList = LgetItem('playgroundList') || [];
const data = playgroundList.find((s) => s.id === modalConfig.id);
setParams(data?.params || {});
}
}, [modalConfig, visible]);
const handleCancel = () => {setVisible(false);
};
return (
<Modal
title="模板预览"
visible={visible}
onCancel={handleCancel}
footer={null}
>
<Form form={normalForm} onAutoSubmit={console.log} {...params.form}>
<SchemaField schema={params.schema} />
<Submit block> 保留 </Submit>
</Form>
</Modal>
);
};
export default Preview;
在应用表单设计器时,便能够应用注入的 scope
值,比方咱们筹备一个 json,抉择一个下拉控件,配置相应器,而后通过咱们注入的申请获取这个 json,展现对应的下拉值:
$effect(() => {
$self.loading = true
$fetch({
url: '/getSelectList',
method: 'get',
params: {}}).then(res => {
$self.loading = false
// 当返回值不是 label 和 value 时转化一下
$self.dataSource = res.map(s => ({ label: res.name, value: res.id}))
}).catch(() => {$self.loading = false})
}, [])
这里的 $fetch
就是咱们注入的申请了
表单配置
- form 提交的 key 为字段标识,可自定义批改,默认为随机字符串
- 题目为 form 表单的 label
-
反对自定义搜寻的,比方 select,须要在组件属性下筛选器中配置表单式,能力反对 label 搜寻
(inputValue, option) => {return option.label.indexOf(inputValue) !== -1; }
- 如果配置了响应器规定中和内部一样的配置,比方组件属性,那么响应器规定中的会笼罩内部的配置(内部的组件属性生效)
高级配置
高级配置在响应器规定中,这里次要针对于一些一般配置无奈实现的性能进行阐明,比方常见的联动,动静取值等场景进行阐明。
$self
为以后选中的表单对象$form
为 form 对象$deps
为依赖对象(需在上方依赖字段配置起源字段)$observable
申明一个可察看对象$effect
和 react 的useEffect
应用相似$values
为提交的 form 表单对象
-
动静枚举值,如果咱们有一个 select 控件,这个控件的值是接口返回的
$effect(() => { $self.loading = true $fetch({ url: '/getSelectList', method: 'get', params: {}}).then(res => { $self.loading = false // 当返回值不是 label 和 value 时转化一下 $self.dataSource = res.map(s => ({ label: res.name, value: res.id})) }).catch(() => {$self.loading = false}) }, [])
-
联动变动枚举值,比方咱们有两个 select,第一个 select 是
mechanism
机构,第一个 select 是user
人员,咱们抉择一个机构后,第二个 select 会依据第一个 select 的值来从接口中获取机构下的人员列表,这是一个比拟常见的联动抉择性能,那么放在表单设计器外面咱们该如何实现呢(实现形式不惟一,这里提供思路)。// 第一个 select,咱们监听 mechanism 的变动,flag 次要利用为跳过首次渲染(保障反显失常展现),当 mechanism 改版(即手动选值)后,清空 user 的取值。$effect(() => { $self.loading = true $fetch({ url: '/getMechanismList', method: 'get', params: {}}).then(res => { $self.loading = false // 当返回值不是 label 和 value 时转化一下 $self.dataSource = res.map(s => ({ label: res.name, value: res.id})) }).catch(() => {$self.loading = false}) }, []) const state = $observable({flag: false}); $effect(() => {if (state.flag) {$form.reset('user'); } state.flag = true; }, [$self.value])
当
mechanism
变动时,清空user
列表,发动申请获取user
列表$effect(() => {$self.dataSource = [] if ($deps.mechanism) { $self.loading = true $fetch({ url: '/getSelectList', method: 'get', params: {mechanism: $deps.mechanism} }).then(res => { $self.loading = false // 当返回值不是 label 和 value 时转化一下 $self.dataSource = res.map(s => ({ label: res.name, value: res.id})) }).catch(() => {$self.loading = false}) } }, [$deps.mechanism])
小试牛刀
咱们应用 mock 数据简略做一个联动
// mock/api.ts
export default {
'GET /api/mechanism': [
{
value: '1',
label: '机构 1',
},
{
value: '2',
label: '机构 2',
},
],
'GET /api/users': (req, res) => {
// 增加跨域申请头
const query: any = req.query;
const user: any = {
'1': [
{
value: '1-1',
label: '机构 1 - 人员 1',
},
{
value: '1-2',
label: '机构 1 - 人员 2',
},
],
'2': [
{
value: '2-1',
label: '机构 2 - 人员 1',
},
{
value: '2-2',
label: '机构 2 - 人员 2',
},
],
};
res.send(user[query.id]);
},
};
咱们定义了两 mock 接口,mechanism
和users
,前者返回一个机构列表,后者依据前者的 id 返回对应的列表,接着咱们在上一期中的预览弹窗中注入申请,这里咱们间接应用 umi 提供的request
。
// Preview.tsx
import {request} from 'umi';
...
const SchemaField = createSchemaField({
components: ...,
scope: {$fetch: request,},
});
最初咱们在表单设计中增加申请
// mechanism
$effect(() => {
$self.loading = true
$fetch("/api/mechanism", {})
.then((res) => {
$self.loading = false
// 当返回值不是 label 和 value 时转化一下
$self.dataSource = res
})
.catch(() => {$self.loading = false})
}, [])
// users
$effect(() => {$self.dataSource = []
if ($deps.mechanism) {
$self.loading = true
$fetch("/api/users", {
params: {id: $deps.mechanism,},
})
.then((res) => {
$self.loading = false
// 当返回值不是 label 和 value 时转化一下
$self.dataSource = res
})
.catch(() => {$self.loading = false})
}
}, [$deps.mechanism])
最初再到表单模板预览一下:
好了,本篇介绍的性能都实现了,那么下一篇咱们将把流程可是化的编辑性能和咱们的表单模板进行关联起来,批改表单模板就能批改节点或连线的属性编辑,达到真正的动静属性编辑成果,纵情期待。
本文地址:链接
本文 github 地址:链接
github demo 地址:链接