基本库使用介绍
先直接上代码
import React, { useState, useMemo } from 'react'
import { createForm, Field, GeneralField, onFieldChange, registerValidateRules } from '@formily/core'
import {
FormProvider,
createSchemaField,
connect,
FormConsumer,
ISchema,
mapProps,
} from '@formily/react'
import { FormLayout, FormItem, Input, FormGrid } from '@formily/antd'
import { Button, Input, Select } from 'antd'
import styles from './index.module.less'
import useDictMap from './hooks/useDictMap'
import TransTypeRadio from './components/TransTypeRadio'
import { DefaultSchema, OtherSchema } from './schemaConfig'
// 全局注入自定义校验
registerValidateRules({
custom1: function(value, rule, ctx, render) {
console.log(value, rule, ctx, render)
return 'sssssss'
}
})
const DynamicRenderer: React.FC = (props) => {
const [schema, setSchema] = useState<ISchema>(DefaultSchema)
// 通过接口获取字典
const dictMap = useDictMap()
const form = useMemo(() => createForm({
effects() {
// 当transType字段发生改变时切换表单元素
onFieldChange('transType', (field: Field) => {
if (field.value === 'I') {
setSchema(OtherSchema)
} else {
setSchema(DefaultSchema)
}
})
}
}), [])
// 通过字典设置options
// connect提供props转换映射。可以使用回调方法映射,也可以使用对象直接映射
const DynamicCSelect = useMemo(() => connect(
Select,
// mapProps({a: 'hahahah'}, (props, field) => {...props})
mapProps({}, (props: any, field: Field) => {
const options = props.options ?? dictMap[props.dictCode]
return {
...props,
options: options || [],
}
}),
// 因为大多数第三方组件都不支持阅读态,如果想要快速支持阅读态的话,即可使用 mapReadPretty 函数来映射一个阅读态组件
// mapReadPretty(TargetComponent, { readPretty: true })
// dictMap为字典转换的key--options
), [dictMap])
const SchemaField = createSchemaField({
components: {
FormItem,
CInput,
CSelect: DynamicCSelect,
Input,
FormGrid,
TransTypeRadio,
},
})
return (
<FormProvider form={form}>
<FormLayout
// 样式自定义修改
className={styles.layout}
layout="inline"
labelAlign="right"
labelWrap
labelWidth={133}
fullness
gridColumnGap={8}
>
<SchemaField schema={schema} />
</FormLayout>
<Button onClick={() => {
console.log(form.values)
}}>click</Button>
</FormProvider>
)
}
export default DynamicRenderer
schema
import { ISchema } from '@formily/react'
import { Field, IGeneralFieldState } from '@formily/core'
type SchemaReactionEffect =
| 'onFieldInit'
| 'onFieldMount'
| 'onFieldUnmount'
| 'onFieldValueChange'
| 'onFieldInputValueChange'
| 'onFieldInitialValueChange'
| 'onFieldValidateStart'
| 'onFieldValidateEnd'
| 'onFieldValidateFailed'
| 'onFieldValidateSuccess'
type SchemaReaction<Field = any> =
| {
dependencies?: string[] | Record<string, string> //依赖的字段路径列表,只能以点路径描述依赖,支持相对路径,如果是数组格式,那么读的时候也是数组格式,如果是对象格式,读的时候也是对象格式,只是对象格式相当于是一个alias
when?: string | boolean //联动条件
target?: string //要操作的字段路径,支持FormPathPattern路径语法,注意:不支持相对路径!!
effects?: SchemaReactionEffect[] //主动模式下的独立生命周期钩子
fulfill?: {
//满足条件
state?: IGeneralFieldState //更新状态
schema?: ISchema //更新Schema
run?: string //执行语句
}
otherwise?: {
//不满足条件
state?: IGeneralFieldState //更新状态
schema?: ISchema //更新Schema
run?: string //执行语句
}
}
| ((field: Field) => void) //可以复杂联动
type SchemaReactions<Field = any> = SchemaReaction<Field> | SchemaReaction<Field>[]
export const DefaultSchema: ISchema = {
type: 'object',
properties: {
grid: {
type: 'void',
'x-component': 'FormGrid',
// 布局,3列
'x-component-props': {
minColumns: 1,
maxColumns: 3
},
properties: {
transType: {
type: 'string',
title: '境内外标志',
default: 'O',
'x-component': 'TransTypeRadio',
'x-decorator': 'FormItem',
'x-decorator-props': {
// 独占三列
gridSpan: 3
},
},
remittanceName1: {
type: 'string',
title: '账号1',
'x-component': 'Select',
'x-decorator': 'FormItem',
'x-component-props': {
dictCode: 'ovs_clear_type',
// options: [
// { label: 'ajsl', value: '1' },
// { label: 'sfgr', value: '2' },
// ],
},
'x-reactions': [
{
dependencies: ['remittanceName2.remittanceName3'],
fulfill: {
schema: {
// 'x-visible': "{{$self.value === $deps[0]}}"
// 'x-visible': "{{'123' == $deps[0]}}",
required: "{{$deps[0] === '222'}}",
},
},
},
(field: Field) => {
const remittanceName = field.query('.remittanceName').value()
if (remittanceName === '周奇霖') {
field.setComponentProps({
options: [{ label: '智障', value: 'zz' }],
})
field.setValue('zz')
} else {
field.setComponentProps({
options: undefined,
})
field.setValue(undefined)
}
},
],
},
remittanceName2: {
type: 'void',
title: '账号2',
'x-decorator': 'FormItem',
'x-component-props': { style: { width: 360 } },
properties: {
['remittanceName2.remittanceName3']: {
type: 'string',
'x-component': 'Input',
'x-component-props': { style: { width: 180 } },
},
['remittanceName2.remittanceName4']: {
type: 'string',
'x-component': 'Input',
'x-component-props': { style: { width: 180 } },
},
},
},
remittanceName5: {
type: 'string',
title: '账号',
'x-component': 'Input',
'x-decorator': 'FormItem',
'x-component-props': { style: { width: 360 } },
},
remittanceName6: {
type: 'string',
title: '账号',
'x-component': 'Input',
'x-validator': [
{
max: 5,
message: '最长5位',
},
],
'x-decorator': 'FormItem',
'x-component-props': { style: { width: 360 } },
},
remittanceName7: {
type: 'string',
title: '账号',
'x-component': 'Input',
'x-decorator': 'FormItem',
'x-component-props': { style: { width: 360 } },
},
},
},
},
}
export const OtherSchema: ISchema = {
type: 'object',
properties: {
grid: {
type: 'void',
'x-component': 'FormGrid',
'x-component-props': {
minColumns: 1,
maxColumns: 3
},
properties: {
transType: {
type: 'string',
title: '境内外标志',
default: 'O',
'x-component': 'TransTypeRadio',
'x-decorator': 'FormItem',
'x-decorator-props': {
gridSpan: 3
},
},
},
},
},
}
自定义组件控制TransType组件
import { Radio, Modal } from 'antd'
import React, { useEffect, useState } from 'react'
import { FormInstance } from 'antd'
import _ from 'lodash'
import { observer, useField, useForm } from '@formily/react'
// 同步observer实现动态监听,可以将observer的值作为useEffect的deps使用
// 类似于直接用antd的useWatch。只不过这里observer双向数据流更方便使用
const TransTypeRadio: React.FC<Props> = observer((props) => {
const { value, onChange } = props
const field = useField()
const form = useForm()
// 境内外标志切换
const handleTransTypeChange = (e) => {
const res = form.values
const initObj = form.initialValues
const initObjKeys = Object.keys(initObj)
const formKeys = Object.keys(res)
const checkKeys = formKeys.filter((item) => initObjKeys.includes(item)) // 需要校验初始值的key
const checkObj = {} // form中对应字段的值组成的对象
checkKeys.forEach((item) => {
checkObj[item] = res[item]
})
const noCheckKeys = formKeys
?.filter((item) => !initObjKeys?.includes(item))
?.filter((item) => !['transType']?.includes(item)) // 不需要校验初始值的key
let checkFlag = true
noCheckKeys?.forEach((item) => {
if (!_.isEmpty(res[item])) {
checkFlag = false
}
})
const initFlag = JSON.stringify(initObj) === JSON.stringify(checkObj) && checkFlag
if (!initFlag) {
Modal.confirm({
title: `确认切换至境${e.target.value === 'O' ? '外' : '内'}汇款?`,
content: '切换后将保留已填内容中可用部分',
okText: '确认',
cancelText: '取消',
centered: true,
onOk: () => {
if (e.target.value === 'O') {
form.setValues({
facilitationFlag: 'N',
remittanceWay: '1',
capFlag: 'N',
residentCountry: ''
})
} else {
form.setValues({
residentCountry: 'CN',
remittanceWay: res.facilitationFlag === 'Y' ? '3' : '2',
})
}
// 重置通过代理行
form.setValues({ proxyFlag: 'N', capFlag: 'N' })
onChange(e.target.value)
},
onCancel: () => {},
})
} else {
onChange(e.target.value)
if (e.target.value === 'O') {
form.setValues({ facilitationFlag: 'N', remittanceWay: '1', capFlag: 'N', residentCountry: '' })
} else {
form.setValues({
residentCountry: 'CN',
remittanceWay: res.facilitationFlag === 'Y' ? '3' : '2',
})
}
// 重置通过代理行
form.setValues({ proxyFlag: 'N', capFlag: 'N' })
}
}
return (
<Radio.Group value={value} onChange={handleTransTypeChange}>
<Radio value={'O'}>境外汇款</Radio>
<Radio value={'I'}>境内汇款</Radio>
</Radio.Group>
)
})
export default TransTypeRadio
type Props = {
value
onChange
}
@formily/core使用
core.formilyjs.org/zh-CN
createForm: 创建一个 Form 实例,作为 ViewModel 给 UI 框架层消费
effects
core核心还提供各种字段变化的回调,栗子中的onFiledChange等effects均是core核心中提供的可以作为主动联动的方法
query core核心提供query查询,其强大的路径系统可以很方便的在各种控制逻辑中获取到ProxyValue
@formily/react
react.formilyjs.org/zh-CN 里面看官网结合栗子即可得出使用方法
@formily/antd
直接接上antd组件库,炫酷
表单联动
-
被动联动:Field Reaction
可以参考文档: react.formilyjs.org/zh-CN/api/s… -
主动联动:effect hooks
a)通过core核心的effects方法,在createForom里对field进行控制。
b)通过自定义组件使用
import React from 'react'
import { createForm, onFieldReact } from '@formily/core'
import { FormProvider, Field, useFormEffects } from '@formily/react'
import { Input, Form } from 'antd'
const form = createForm({
effects() {
onFieldReact('custom.aa', (field) => {
field.value = field.query('input').get('value')
})
},
})
const Custom = () => {
useFormEffects(() => {
onFieldReact('custom.bb', (field) => {
field.value = field.query('.aa').get('value')
})
})
return (
<div>
<Field name="aa" decorator={[Form.Item]} component={[Input]} />
<Field name="bb" decorator={[Form.Item]} component={[Input]} />
</div>
)
}
export default () => (
<FormProvider form={form}>
<Field name="input" decorator={[Form.Item]} component={[Input]} />
<Field name="custom" decorator={[Form.Item]} component={[Custom]} />
</FormProvider>
)