前言
Formily是阿里开源的动态化表单的解决方案,优雅的解决了多种复杂场景的表单的数据、状态管理及夸表单通信问题,同时规避了全量渲染的弊端,性能优越。刚好满足我近期工作中的业务需求,啃了将近一周的文档,对Family有了初步的了解,后续使用起来有时间再出翻坑指南。
初步了解
Formily基于MVVM的设计原则,常用的基础核心库有@formily/core、@formily/react、@formily/vue、@formily/antd,支持react和vue,同时支持Markup Schema、 JSX以及现在业界最流行的JSON Schema的写法。
Formily 分为了内核层,UI 桥接层,扩展组件层,和配置应用层,如下图。
内核层是 UI 无关的,它保证了用户管理的逻辑和状态是不耦合任何一个框架。
JSON Schema 独立存在,给 UI 桥接层消费,保证了协议驱动在不同 UI 框架下的绝对一致性,不需要重复实现协议解析逻辑。
扩展组件层,提供一系列表单场景化组件,保证用户开箱即用。无需花大量时间做二次开发。
核心优势
- 高性能
- 开箱即用
- 联动逻辑实现高效
- 跨端能力,逻辑可跨框架,跨终端复用
- 动态渲染能力
核心劣势:学习成本较高,需引多个包,包体积较大。
确实Formily的学习成本还是相对较高的,几大核心库一堆的文档和API会让你眼花缭乱,但是既然要学就要耐下心来,思路理清之后就轻车熟路了。
核心库介绍:@formily/core:ViewModel层,负责管理表单的状态,表单校验,联动等等。@formily/react: Model层,作为UI 库来接入内核数据,用来实现最终的表单交互效果,对于不同框架的用户,使用有不同的桥接库,这里使用react为例,使用vue安装@formily/vue。@formily/antd:View层,在Ant Design基础之上封装的开箱即用的组件库。
使用准备
安装依赖,这里以React+Antd为例
使用yarnyarn add @formily/coreyarn add @formily/reactyarn add antd moment @formily/antd
or使用npmnpm install --save @formily/corenpm install --save @formily/reactnpm install --save antd moment @formily/antd
导入依赖:
import React from 'react'import { createForm } from '@formily/core'import { FormProvider, Field } from '@formily/react'import { FormItem, Input } from '@formily/antd'
实例
以JSON Schema写法为例:
import React from 'react';import { createForm } from '@formily/core';import { createSchemaField, FormConsumer, FormProvider } from '@formily/react';import { FormItem, Input, Password, Submit, FormLayout, FormButtonGroup } from '@formily/antd';import * as ICONS from '@ant-design/icons';//用来创建表单核心领域模型,它是作为MVVM设计模式的标准 ViewModelconst form = createForm();// 创建一个 SchemaField 组件用于解析JSON-Schema动态渲染表单的组件const SchemaField = createSchemaField({// 组件列表components: {FormLayout,FormItem,Input,Password,},// 全局作用域,用于实现协议表达式变量注入scope: {icon(name: string) {return React.createElement(ICONS[name]);},},});/**初始化一份json schema* 解析 json-schema 的能力;将 json-schema 转换成 Field Model 的能力;编译 json-schema 表达式的能力**/const schema = {// schema typetype: 'object',properties: {layout: {type: 'void','x-component': 'FormLayout','x-component-props': {labelCol: 2,wrapperCol: 6,labelAlign: 'right',// layout: 'vertical',},// 属性描述properties: {username: {// schema typetype: 'string',// 标题title: '用户名',// 必填required: true,// 字段 UI 包装器组件'x-decorator': 'FormItem',// 字段 UI 组件'x-component': 'Input',// 字段 UI 组件属性'x-component-props': {prefix: "{{icon('UserOutlined')}}",},},password: {type: 'string',title: '密码',required: true,'x-decorator': 'FormItem','x-decorator-props': {addonAfter: '强度高',},'x-component': 'Password','x-component-props': {prefix: "{{icon('LockOutlined')}}",},},},},},};export default () => {return (<FormProvider form={form}><FormLayout layout="vertical"><SchemaField schema={schema} /></FormLayout><FormButtonGroup><Submit onSubmit={console.log}>提交</Submit></FormButtonGroup><FormConsumer>{() => (<divstyle={{width: 340,marginTop: 20,padding: 5,border: '1px dashed #666',}}>实时响应-用户名:{form.values.username}</div>)}</FormConsumer></FormProvider>);};

FormProvider组件是作为视图层桥接表单模型的入口,它只有一个参数,就是接收createForm创建出来的Form实例,并将Form实例以上下文形式传递到子组件中。FormLayout组件是用来批量控制FormItem样式的组件,这里我们指定布局为水平布局,也就是标签在左,组件在右。FormConsumer组件是作为响应式模型的响应器而存在,它核心是一个render props模式,在作为children的回调函数中,会自动收集所有依赖,如果依赖发生变化,则会重新渲染,借助FormConsumer我们可以很方便的实现各种计算汇总的需求。FormButtonGroup组件作为表单按钮组容器而存在,主要负责按钮的布局。Submit组件作为表单提交的动作触发器而存在,其实我们也可以直接使用form.submit方法进行提交,但是使用Submit的好处是不需要每次都在Button组件上写onClick事件处理器,同时它还处理了Form的loading状态,如果onSubmit方法返回一个Promise,且Promise正在pending状态,那么按钮会自动进入loading状态。
注意:使用前还需要了解,Formily已经完全放弃对IE的兼容,如需兼容IE,慎用!!!
