Formily快速上手实践

1,900 阅读7分钟

一、引言

系统性学习formily,包含Scheme、校验、赋值、布局、自定义表单项、联动等,本文重点聚焦schema模式的api介绍

二、formily结构

2.1 初始化模版

formily schema模式下模版如下代码

import { createForm, onFieldChange, onFieldValueChange } from '@formily/core';
import { FormProvider, createSchemaField } from '@formily/react';
import { FormItem, Input } from "antd";

const Test = () => {
//1. 创建form实例
const form = createForm({})
//2. 创建shchema组件
const SchemaField = createSchemaField({
    components:{
      FormItem,
      Input,
      Select,
      Checkbox
     }
})
//3. 创建schema
const schema = {
    type:'object'
    properties:{
        name:{
            type:'string',
            title:'姓名',
            required: true,
            'x-decorator':'FormItem',
            'x-component':'Input',
      },
    }
}
    return (
        <FormProvider form={form}>
           <SchemaField schema={schema} />
        </FormProvider>
    )
}

2.2 表单结构

表单结构分为简单布局与嵌套布局

2.2.1 简单结构

顶层type表示容器节点,properties对象告诉formily其内部用于定义具体表单字段。

{
    type:'object',
    properties:{
        name:{
            type:'string',
            title:'姓名',
            'x-decorator':'FormItem',
            'x-component':'Input',
        },
        age:{
            type:'number',
            title:'年龄',
            'x-decorator':'FormItem',
            'x-component':'InputNumber',
        }
    }
}
截屏2025-11-20 23.28.37.png

2.2.1 嵌套结构

formily的schema支持嵌套结构,实现思路十分简单,在properties内部继续递归的定义新的表单项组成

例如想实现如下结构表单,姓名表单与下面容器平级,容器内部又有两个表单项。只需在第一层的properties内部继续嵌套新的表单结构即可。

image.png

const schema1 = {
    type:'object',
    properties:{
      name:{
        type:'string',
        title:'姓名',
        required: true,
        'x-decorator':'FormItem',
        'x-component':'Input',
      },
      part1:{
        type:'void',
        'x-component':'Part1', //自定义组件容器,承载新表单项
        properties:{
          part11:{
            type:'string',
            title:'part11',
            required: true,
            'x-decorator':'FormItem',
            'x-component':'Input',
          },
          part12:{
            type:'string',
            title:'part12',
            required: true,
            'x-decorator':'FormItem',
            'x-component':'Input',
          },
        },
      }
    },
  }
  
  
  //自定义容器组件
  const Part1 = (props:any) => {
    return (
      <>
      <div>第一部分</div>
      <div style={{padding: '10px 0 10px 30px'}}>{props.children}</div>
      </>
    )
  }

三、核心API

3.1 submit

submit方法可以同时实现两个功能校验+表单值获取。

import { createForm, onFieldChange, onFieldValueChange } from '@formily/core';
import { FormProvider, createSchemaField } from '@formily/react';
import { FormItem, Input } from "antd";

const Test = () => {
//1. 创建form实例
const form = createForm({})
//2. 创建shchema组件
const SchemaField = createSchemaField({
    components:{
      FormItem,
      Input,
      Select,
      Checkbox
     }
})
//3. 创建schema
const schema = {
    type:'object'
    properties:{
        name:{
            type:'string',
            title:'姓名',
            required: true,
            'x-decorator':'FormItem',
            'x-component':'Input',
      },
    }
}

// 表单提交
const onSubmit = async()=> {
    try{
        const res = await form.submit()
    }catch(e){
        throw new Error('校验失败')
    }
}
    return (
        <FormProvider form={form}>
           <SchemaField schema={schema} />
           <div>
               <Button onClick={onSubmit}>提交</Button>
           </div>
        </FormProvider>
    )
}

3.2 reset

reset实现表单项的重置功能

// 表单重置
const onReset = ()=> {
    form.reset();
}
return (
    <FormProvider form={form}>
       <SchemaField schema={schema} />
       <div>
           <Button onClick={onReset}>重置</Button>
       </div>
    </FormProvider>
)
}

3.3 setValues

setValues是给表单项赋值使用,通常用于详情、编辑页中批量的给多个字段赋值。特别注意,表单项赋值时路径为void字段的需要忽略

案例1:批量给多个表单项赋值


useEffect(()=>{
    form.setValuse({name:'dzp',age:20})
},[form])


/*schema结构*/
const schema = {
    type: 'object',
    properties: {
      name: {
        type: 'string',
        title: '姓名',
        required: true,
        'x-decorator': 'FormItem',
        'x-component': 'Input',
        'x-component-props': {
          placeholder: '请输入姓名',
        },
      },
      age: {
        type: 'number',
        title: '年龄',
        required: true,
        'x-decorator': 'FormItem',
        'x-component': 'InputNumber',
      },
    },
  }

案例2:嵌套表单项赋值

如下是一段schema表单项,既有嵌套,又有void类型字段,牢记赋值时void类型的字段直接忽略。

const schema = {
    type: 'object',
    properties: {
      name: {
        type: 'string',
        title: '姓名',
        required: true,
        'x-decorator': 'FormItem',
        'x-component': 'Input',
        'x-component-props': {
          placeholder: '请输入姓名',
        },
      },
      info1:{
        type:"void",
        properties:{
          name1:{
            type:"string",
            title:"姓名1",
            required: true,
            'x-decorator':'FormItem',
            'x-component':'Input',
          },
          info2:{
            type:'object',
            properties:{  
              name2:{
                type:"string",
                title:"姓名2",
                required: true,
                'x-decorator':'FormItem',
                'x-component':'Input',
              },
            },
          }
        }
      },
      email: {
        type: 'string',
        title: '邮箱',
        required: true,
        'x-decorator': 'FormItem',
        'x-component': 'Input',
        'x-component-props': {
          placeholder: '请输入邮箱',
        },
      },
    },
  }

根据规律,给表单项赋值时从根节点依次遍历,遇到类型是void的直接忽略,遇到object类型的视作对象。最终赋值结果如下:

form.setValues({
    name:'name1',
    name1:'name11',
    info2:{
        name2:'name2'
    },
    email:'test'
})

3.4 useForm

useForm可以获取form实例,通常用于自定义组件中获取表单实例对象。

import {useForm} from "@formily/react"
const Container = (props) => {
    const form = useForm()
    const onSubmit = () => {
        if(form){
            form.submit()
        }
    }
    return (
        <div>
            {props?.children}
            <div onClick={onSubmit}>提交</div>
        </div>
    )
}

3.5 setFormState

设置表单的状态,禁用态、只读态等;常用在根据页面类型统一设置表单状态案例中。

特殊:setFormState设置的表单状态优先级低于schema表单项状态设置

  1. API使用
form.setFormState({disabled:true})//查看页设置页面禁止

2. setFormState与schema同时设置了状态

如下案例展示通过setFormState设置所有表单项状态是禁止,但是name1内部设置非禁止态,因此name1是非禁止,name2是禁止。

form.setFormState({disabled:true}
const schema = {
    type:'object',
    properties:{
        name1:{
            type:'string',
            component:'Input',
            'x-disabled':false
        },
        name2:{
            type:'string',
            component:'Input',
        }
    }
}

四、schema核心参数

schema结构由如下几部分组成

  1. type:类型,例如object、string、number
  2. properties:定义表单存在哪些表单元素,例如如下代码properties内部定义了一个Input和InputNumber表单项
  3. x-decorator:定义表单项
  4. x-decorator-props:修饰整个表单项FormItem内容、样式等
  5. x-component:定义组件类型
  6. x-component-props:定义组件参数
  7. x-reactions:处理联动、state、schema更新等复杂逻辑
  8. x-disabled:处理禁止项
  9. x-display:显示隐藏
  10. x-validator:校验
  11. x-reactions:联动等复杂场景

4.1 x-decorator-props

x-decorator-props用于修饰表单项的样式、标签、内容等。表单项=标签+表单,因此不要混淆表单项与表单的概念。其常见属性有

  1. label:字符串或自定义组件
  2. labelCol:标签宽度
  3. labelAlign:left | right 标签对齐方式
  4. tooltip:标签旁的提示信息
  5. style:样式
  6. className:类名
    const schema = {
        type:'object',
        properties: {
          name: {
            type: 'string',
            'x-decorator': 'FormItem',
            'x-component': 'Input',
            'x-decorator-props':{
              style:{
                color:'red',
              },
              className:'custom-form-item',
              label:'姓名',
              labelAlign:'left',
            }
          },     
        }, 
    }  
image.png

4.2 x-component-props

x-component-props用于修饰表单的属性,常见属性参数有如下

  1. disabled
  2. placeholder
  3. style
  4. className
    const schema = {
        type:'object',
        properties: {
          name: {
            type: 'string',
            'x-decorator': 'FormItem',
            'x-component': 'Input',
            'x-component-props':{
              disabled:true,
              placeholder:'输入内容',
              style:{},
              className:'xx'
            }
          },     
        }, 
    }

4.3 x-disabled

x-disabled用于控制表单项的禁用,其参数是boolean值

const schema = {
    type:'object',
    properties: {
      name: {
        type: 'string',
        'x-decorator': 'FormItem',
        'x-component': 'Input',
        'x-disabled':false
      },     
    }, 
}

4.4 x-validator

x-validator用于表单项的校验,其参数是数组表示可以添加多个校验规则。校验规则分为两种,一种是必填校验,另一种是自定义校验,其中自定义校验函数的参数如下

validator:(value,rule,ctx)=>{}

参数1:表单项的值
参数2:规则
参数3:表单实例,其中ctx.form.values可以获取表单所有的值
email: {
    type: 'string',
    title: '邮箱',
    'x-decorator': 'FormItem',
    'x-component': 'Input',
    x-validator':[
      {
          required:true,
          message:'邮箱必须输入'
      },
      {
        validator: (value,rules,ctx) {
            if(!value) return '不能是空'
            if(!ctx.form.values.password) {
                return '密码不能是空'
            }
            return true
        }
      },
    ],
   },

4.5 default

default为表单项设置默认值

const schema = {
    type:'object',
    properties: {
      name: {
        type: 'string',
        'x-decorator': 'FormItem',
        'x-component': 'Input',
        'default':'test'
      },     
    }, 
}

4.6 x-display

x-display控制表单项的展示隐藏,其取值有三种

  1. none:删除表单项,表单没有当前表单项
  2. hidden:隐藏表单项,表单项仍然存在在表单中
  3. visible:显示表单项,默认即显示
const schema = {
    type:'object',
    properties: {
      name: {
        type: 'string',
        'x-decorator': 'FormItem',
        'x-component': 'Input',
        'x-display':'none'
      },     
    }, 
}

4.7 x-reactions

x-reactions是formily高级api,可以实现表单联动、表单状态更新、schema更新等复杂场景。

4.7.1 基本结构

x-reactions可以传对象,也可以传数组对象,对象结构由以下4个模块构成。

  1. dependencies 依赖的表单项字段
  2. when 判断条件
  3. fulfill:条件成立执行其内部操作
  4. otherwise:条件不成立时,执行其内部操作
'x-reactions':[
    {
        dependencies:['.name'],
        when:'{{$deps[0] === "dzp"}}',
        fulfill:{
          state:{},//表单项属性
          schema:{},//表单项schema
          run:'{{console.log("run1", $deps[0])}}'//函数执行
        },
        otherwise:{
          state:{},
          schema:{},
          run:'{{console.log("run2", $deps[0])}}'
        },
    }
]

4.7.2 run执行

run的执行有两种情况,一种是没有when,一种是有when。

  1. 没有when:初始就执行、且依赖性发生变化就执行

初始页面加载执行run函数,表单项name每次输入变更都会执行run函数

'x-reactions':[
    {
        dependencies:['.name'],
        fulfill:{
          run:'{{console.log("run1", $deps[0])}}'//函数执行
        }
    }
]
  1. 有when:仅当when条件成立才执行run

表单项name的值输入是dzp时,才执行了run函数

'x-reactions':[
    {
        dependencies:['.name'],
        when:'{{$deps[0] === "dzp"}}',
        fulfill:{
          run:'{{console.log("run1", $deps[0])}}'//函数执行
        }
    }
]

4.7.3 fulfill

fulfill内部的state和schema包含许多内容,下面列举常见的

schema

  1. 'x-component'
  2. default
  3. 'x-disabled'

state

  1. value
  2. disabled
  3. display
  4. componentProps

如下案例实现功能是:当姓名表单项输入dzp时,年龄表单项值填充123,且禁用,且标签更改成姓名2

const schema = {
    type:'object',
    properties:{
      name:{
        type:'string',
        title:'姓名',
        'x-decorator':'FormItem',
        'x-component':'Input',
      },
      age:{
        type:'string',
        title:'年龄',
        'x-decorator':'FormItem',
        'x-component':'Input',
        'x-reactions':[
          {
            dependencies:['.name'],
            when:'{{$deps[0] === "dzp"}}',
            fulfill:{
              state:{
                value:123,
              },
              schema:{
                'x-disabled':true,
                'x-decorator-props':{
                  label:'姓名2',
                },
              },
            },
          },
        ],
      },
    },
  } 

4.7.4 特殊场景

x-reactions可以直接传1个函数,主要用于异步数据加载、复杂场景处理等,十分的常见。

案例:异步加载select组件数据

const dzpFun = (field) => {
  await new Promise((resolve) => setTimeout(resolve, 500));
  const options = [
    { label: '大周平', value: 'dzp' },
    { label: '周老板', value: 'boss' },
  ];
  field.setComponentProps({
    options,
  });
}


/*schema*/
const schema = {
    type:'object',
    properties:{
      city:{
        type:'array',
        title:'城市',
        'x-decorator':'FormItem',
        'x-component':'Select',
        'x-reactions':'{{dzpFun}}'
      },
    },
  } 
  

五、scope

scope是schema中用于访问外部变量和函数的桥梁,schema中所有通过'{{}}'定义的都是函数与变量都是scope的。特殊点:schema所有的动态属性也都必须使用'{{}}'操作

5.1 使用

scope的使用格式只有一种如下,即字符串模版

'{{name}}'//变量
'{{getName("test")}}'//方法

5.2 常见案例

  1. 在scope中定义表单校验方法并使用
// scope中定义的函数
const myValidator = (value: string,rule:any,ctx:any) => {
    if (!value || !value.trim()) {
      return '姓名不能是空';
    }
    if (value === '123') {
      return '姓名不能是123';
    }
    return true; // 校验通过
  };
  
  
// schema中调用
const schema = {
    type: 'object',
    properties: {
      name: {
        type: 'string',
        title: '姓名',
        'x-decorator': 'FormItem',
        'x-component': 'Input',
        'x-validator': [
          {
            validator: '{{myValidator}}'
          }
        ],
      },
    },
  };

2. scope变量控制表单项的联动、禁止、默认值等

//scope
const isDisabled = true;
const status = 'visible'; // 'visible' | 'hidden' | 'none'
const defaultV = 'dzp';


//schema
const schema = {
    type: 'object',
    properties: {
      name: {
        type: 'string',
        title: '姓名',
        'x-decorator': 'FormItem',
        'x-component': 'Input',
        'x-component-props': {
          placeholder: '请输入姓名',
        },
        'x-disabled': '{{isDisabled}}',
        'x-display': '{{status}}',
        "default": '{{defaultV}}',
      },
    },
  };


六、特殊指令

6.1 $self

$self 代表当前字段的实例对象,可在字符串表达式中访问字段的状态、值和方法。

  1. $self.value 当前表单项的值
const schema = {
    type:'object',
    properties:{
      name:{
        type:'string',
        title:'姓名',
        'x-decorator':'FormItem',
        'x-component':'Input',
        'x-disabled':'{{$self.value === "dzp"}}',
      },
    },
  } 

6.2 $deps

$deps 是一个数组,包含 dependencies 中声明的依赖字段的值,按声明顺序排列。使用时按数组下标获取

'x-reactions': [
  {
    dependencies: ['.name', '.age', '.email'],  // 声明依赖
    when:'{{$deps[0]==="xxx"}}'//第一个依赖name
    when:'{{$deps[1]==="xxx"}}'//第二个依赖age
  }
]