Loading...

# formily 表单初识

# 背景

Formily 是 alibaba 开源表单框架,抽象了表单领域模型的 MVVM 表单解决方案。

这里引用官网的介绍:

众所周知,表单场景一直都是前端中后台领域最复杂的场景,它的复杂度主要在哪里呢?

  • 字段数量多,如何让性能不随字段数量增加而变差?

  • 字段关联逻辑复杂,如何更简单的实现复杂的联动逻辑?字段与字段关联时,如何保证不影响表单性能?

    • 一对多 (异步)
    • 多对一 (异步)
    • 多对多 (异步)
  • 表单数据管理复杂

    • 表单值转换逻辑复杂 (前后端格式不一致)
    • 同步默认值与异步默认值合并逻辑复杂
    • 跨表单数据通信,如何让性能不随字段数量增加而变差?
  • 表单状态管理复杂

    • 着重提自增列表场景,如何让数组数据在移动,删除过程中,字段状态能够做到跟随移动?
  • 表单的场景化复用

    • 查询列表
    • 弹窗 / 抽屉表单
    • 分步表单
    • 选项卡表单
  • 动态渲染诉求很强烈

    • 字段配置化,让非专业前端也能快速搭建复杂表单
    • 跨端渲染,一份 JSON Schema,多端适配
    • 如何在表单协议中描述布局?
      • 纵向布局
      • 横向布局
      • 网格布局
      • 弹性布局
      • 自由布局
    • 如何在表单协议中描述逻辑?

# 快速开始

对于 react 用户来说, antd 是应用最为广泛的 UI 库之一。 @formily/antd-v5 是基于 Ant Design V5 封装的针对表单场景专业级组件库。

npm install --save antd dayjs
npm install --save @formily/core @formily/react @formily/antd-v5

# JSON Schema 渲染模式

Formily 支持 3 种渲染模式, JSXMarkup SchemaJSON Schema 。这里主要介绍最后一种 JSON Schema

Formily 提供了一套  DSL ,可以通过 JSON 渲染表单结构。

下面是一个最简的 formily 定义的 JSON schema ,以下 JSON 便可描述 form 的结构。

const normalSchema = {
  type: "object",
  properties: {
    username: {
      type: "array",
      title: "Username",
      required: true,
      "x-decorator": "FormItem",
      "x-component": "Input",
      'x-component-props': {
        prefix: "{{icon('UserOutlined')}}",
      },
    },
    password: {
      type: "string",
      title: "Password",
      required: true,
      "x-decorator": "FormItem",
      "x-component": "Password",
      'x-component-props': {
        prefix:  "{{icon('LockOutlined')}}",
      },
    }
  }
};

有了 json schema 定义的表格结构之后,要创建出表格还需要如下的操作

const SchemaField = createSchemaField({
  components: {
    FormItem,
    Input,
    Password,
    ArrayCards
  },
  scope: {
    icon(name: string) {
      return React.createElement(ICONS[name]);
    }
  }
});
const form = createForm();
export default function App() {
  return (
    <div className="App">
      <FormProvider form={form}>
        <SchemaField schema={normalSchema} />
        <FormButtonGroup>
          <Submit onSubmit={console.log}>提交</Submit>
        </FormButtonGroup>
      </FormProvider>
    </div>
  );
}

其生成的表格如下表所示,源代码地址:formilyTest - CodeSandbox
表格实例1

# SchemaField

SchemaField 组件是专门用于解析 JSON-Schema 动态渲染表单的组件。 在使用 SchemaField 组件的时候,需要通过 createSchemaField 工厂函数创建一个 SchemaField 组件。

其接收两个参数 , components 对应内部需要用到的组件,可以是 antd 的组件,也可以是自定义的组件。 scope 对应的是注入的变量,比如国际化时,可以将 locale 等传入。

components?: Components;  
scope?: any;

# 使用场景

# 自定义校验

很多时候需要自定义校验规则和校验文案,

那么首先看一下预设的校验规则

// 字符串型格式校验器
type ValidatorFormats =
  | 'url'
  | 'email'
  | 'ipv6'
  | 'ipv4'
  | 'number'
  | 'integer'
  | 'idcard'
  | 'qq'
  | 'phone'
  | 'money'
  | 'zh'
  | 'date'
  | 'zip'
  | (string & {}) // 其他格式校验器需要通过 registerValidateFormats 进行注册
// 对象型校验结果
interface IValidateResult {
  type: 'error' | 'warning' | 'success' | (string & {})
  message: string
}
// 对象型校验器
interface IValidatorRules<Context = any> {
  triggerType?: 'onInput' | 'onFocus' | 'onBlur'
  format?: ValidatorFormats
  validator?: ValidatorFunction<Context>
  required?: boolean
  pattern?: RegExp | string
  max?: number
  maximum?: number
  exclusiveMaximum?: number
  exclusiveMinimum?: number
  minimum?: number
  min?: number
  len?: number
  whitespace?: boolean
  enum?: any[]
  const?: any
  multipleOf?: number
  uniqueItems?: boolean
  maxProperties?: number
  minProperties?: number
  maxItems?: number
  maxLength?: number
  minItems?: number
  minLength?: number
  message?: string
  [key: string]: any // 其他属性需要通过 registerValidateRules 进行注册
}
// 函数型校验器校验结果类型
type ValidatorFunctionResponse = null | string | boolean | IValidateResult
// 函数型校验器
type ValidatorFunction<Context = any> = (
  value: any,
  rule: IValidatorRules<Context>,
  ctx: Context
) => ValidatorFunctionResponse | Promise<ValidatorFunctionResponse> | null
// 非数组型校验器
type ValidatorDescription =
  | ValidatorFormats
  | ValidatorFunction<Context>
  | IValidatorRules<Context>
// 数组型校验器
type MultiValidator<Context = any> = ValidatorDescription<Context>[]
type FieldValidator<Context = any> =
  | ValidatorDescription<Context>
  | MultiValidator<Context>

这里首先考虑如下的校验规则,错误提示有两种 自定义非空校验规则固定值校验 ,并且都有对应的 message 信息,那么其 schema 可由此给出

const schema: ISchema = {
  type: 'object',
  properties: {
    input: {
      type: 'string',
      title: '输入框',
      'x-decorator': 'FormItem',
      'x-component': 'Input',
      'x-component-props': {
        style: {
          width: 240,
        },
      },
      'x-validator':[
        {
          required: true,
          message:'自定义非空校验规则'
        },
        {
        validator: `{{(value, rule)=> {
          if (!value) return ''
          return value !== '123' ? '请填写123' : ''
        }}}`,
      }]
    },
    textarea: {
      type: 'string',
      title: '文本框',
      required: true,
      'x-decorator': 'FormItem',
      'x-component': 'Input.TextArea',
      'x-component-props': {
        style: {
          width: 400,
        },
      },
    },
  },
}

我们可以看一下对应的效果

自定义校验规则

可以看到上图右边出现两种校验错误信息,其对应的验证器为如下所示,

'x-validator':[
        {
          required: true,
          message:'自定义非空校验规则'
        },
        {
        validator: `{{(value, rule)=> {
          if (!value) return '请填写123'
          return value !== '123' ? '请填写123' : ''
        }}}`,
      }]

通过这个也可以看出,多个验证器存在时,错误信息也可能会存在多个,写的时候需要进行额外注意。

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

jluyeyu 微信支付

微信支付

jluyeyu 支付宝

支付宝