UNPKG

@ice/form

Version:
207 lines (168 loc) 9.84 kB
--- title: IceForm category: Components chinese: 表单组件 --- 表单组件 ## 参数(Props) | 参数名 | 说明 | 必填 | 类型 | 默认值 | 备注 | | ------ | ---- | ---- | ---- | ------ | ---- | | initialValues | 表单初始值 | N | object | {} | - | | onSubmit | submit函数 | Y | function | - | - | | onChange | 表单变化回调 | N | function | - | function(values: object, item: object) => void <br> 参数: <br> values: {object} 表单数据 <br> item: {object} 详细 <br> item.name: {string} 变化的组件名 <br> item.value: {string} 变化的数据 | | rules | 校验规则 | N | object | {} | - | | effects | 联动规则 | N | array | [] | - | | layout | 表单布局 | N | object | | - | | renderField | 自定义 Field 布局 | N | function | - | function({label, component, error}) => dom <br> 参数: <br> label: {string/element} Field 的 label <br> component: {string/function} 待渲染的控件 <br> error: {string/element} Field 错误提示信息 | 其他属性比如 `style`、`className` 等均会传递到 `form` 标签上。 `layout` 是个对象,包含 4 个属性: ```js { labelAlign: 'left', // label 的位置,'left'、'top',默认 'left' labelTextAlign: 'right', // label 文字对齐方式,'left'、'right',默认 'right' labelCol: 1, // label 占的栅格宽度,共 12 等分,默认 2 wrapperCol: 3, // 控件占的栅格宽度,共 12 等分,默认 6 } ``` `rules` 是一个 Object,`key` 是 `<Field>` 的 `name` 属性值,`value` 是个数组,数组里面的每一项是一个校验规则,参考 [async-validator](https://github.com/yiminghe/async-validator)。 ```js <Form onSubmit={this.onSubmit} style={{color: '#ee7893'}} rules={{ username: [{ required: true, min: 5, message: '姓名至少5个字符' }], age: [{ required: true, message: '年龄必填' }] }} > <Field label="姓名:" name="username" component="input" type="text" /> <Field label="年龄:" name="age" component='input' type="number" /> </Form> ``` `effects` 是个数组,写法如下: ```js <Form onSubmit={this.onSubmit} effects={[ { field: 'username', handler: formCore => { if (formCore.getFieldValue('username') === 'ice') { formCore.setFieldValue('age', 2) } } } ]} > <div>Hello Form</div> <Field label="姓名:" name="username" component="input" type="text" /> <Field label="年龄:" name="age" component='input' type="number" /> <button type="submit">Submit</button> </Form> ``` 监听该 `field` 的 `onChange` 事件,然后设置其他表单项的数据,从而达到联动效果。`handler` 的参数是 `formCore` 对象,该对象暴露一些 api 可以设置 value、error、show/hide 等。 ## Field 组件 | 参数名 | 说明 | 必填 | 类型 | 默认值 | 备注 | | ------ | ---- | ---- | ---- | ------ | ---- | | label | 表单项的 label | N | string/element | - | - | | name | 表单项的 name | Y | string | - | - | | component | 表单类型,原生 html 标签或者三方组件 | N | string/function | - | 'input' 'textarea' Input Radio | | value | 表单项的值 | N | - | '' | - | | rules | 校验规则 | N | object or array | - | - | | effects | 联动规则 | N | object | - | - | | visible | 显示隐藏当前 Field | N | boolean | true | true/false | | setValueFormatter | 格式化控件渲染值 | N | function | | function(savedValue) => renderValue | | getValueFormatter | 格式化控件提交值 | N | function | | function(renderValue) => savedValue | | layout | 设置当前 Field 的布局 | N | object | 同 Form layout | 当前 Field 的 layout 会覆盖 Form 的 layout | | tips | 提示信息 | N | string | | | | valueName | 控件值的名称,比如,radio 的 valueName 为 'checked',value 为 true/false | N | string | | 比如 Fusion 的 Switch 组件 | | errorRender | 自定义 error 渲染 | N | function(error) {} | | | | onChange | 自定义 onChange 函数 | N | function() {} | | 默认情况下已处理表单的 onChange(eventOrValue) 事件,如果接入的三方控件 onChange 的第一个参数不是 event 或者 value,可以主动设置对应的值。比如,接入控件的 onChange(xxx, value) 第二个参数才是 value,则可以手动设置 `formCore.setValue(fieldname, value)` | `style`、`className` 属性会传递到 Field 最外层 dom 上,其他属性会传递到 `component` 上,如果没有 `component` 但有 `children`,则属性传递到 `children` 上。 `Field` 的 `rules` 和 `effects` 不需要 `name` 作为 key 了,写法如下: ```js <Form onSubmit={this.onSubmit}> <Field label="姓名:" name="username" component="input" type="text" /> <Field label="昵称:" name="nickname" component="input" type="text" effects={{ handler: formCore => { if (formCore.getFieldValue('nickname') === 'snow') { formCore.setFieldProps('age', { visible: true, }); } else { formCore.setFieldProps('age', { visible: false, }); } } }} /> <Field label="年龄:" name="age" component='input' type="number" rules={[{ required: true, message: '年龄必填' }]} /> <button type="submit">Submit</button> </Form> ``` ## FieldArray 组件 FieldArray 表示渲染数组类型的数据,属性同 Field: ```js <Form onSubmit={this.onSubmit} > <FieldArray label="新增顾客:" name="customers"> <Field name="customer0" component={Input} placeholder="customer name" /> <Field name="customer1" component={Input} placeholder="customer name" /> <Field name="customer2" component={Input} placeholder="customer name" /> </FieldArray> <Field label="日期:" name="date" component={DatePicker} /> <Field label=""> <Button htmlType="submit">Submit</Button> </Field> </Form> ``` ## `formCore` API `formCore` 会暴露一些 API,使用这些 API 可以获取、设置表单的数据、状态等。 - `getFieldValue(name)`:获取某一 `Field` 的值 - `setFieldValue(name, value)`:设置某一 `Field` 的值 - `getValues()`:获取表单的 values - `setValues(values, runEffects)`:设置表单的 values,runEffects 为 Boolean,表示设置 values 之后是否需要执行表单的 effects,默认 false - `getFieldError(name)`:获取某一 `Field` 的 error 信息 - `setFieldError(name, errMsg)`:设置某一 `Field` 的 error 信息 - `getErrors()`:获取所有 `Field` 的 error 信息 - `setErrors(errors)`:设置某些 `Field` 的 error 信息 - `getFieldProps(name)`:获取某一 `Field` 的属性值 - `setFieldProps(name, prop)`:设置某一 `Field` 的属性值 - `submit()`:提交表单 - `reset(initialValues)`:重置表单值为表单初始化时的默认值,如果表单初始化时没有默认值,则清空表单;如果传了参数 initialValues,则 initialValues 会成为新的表单默认值 也可以通过属性的方式获取到一些数据: - `formCore.values`:获取表单的所有值 - `formCore.errors`:获取表单校验的错误信息 - `formCore.pristine`:表单当前的 `values` 是否与 `initialValues` 相等 ## 延伸阅读 ### 开发 @ice/form 表单背景 对于前端,表单开发是一件特别繁琐的事情,尤其在中后台业务中,大家常常会被各种五花八门的表单折磨,又不得不面对现实地去寻找最佳方案,但最终都会发现过度设计的表单组件性能不好,使用简单的表单组件还是需要写大量的业务代码。经过长期的积累以及在社区的调研,我们开发了一个表单组件帮助大家快速地创建一个高性能表单。 ### 组件特性 - 内部几乎无依赖,体积小 - 内部管理表单状态,提升开发效率 - 使用观察者模式提升表单性能 - 强大的校验以及声明式联动 - 可结合第三方组件库(Next、Antd) - 可自定义 Field ### 架构方案 ![](https://img.alicdn.com/tfs/TB1gFAvaUGF3KVjSZFoXXbmpFXa-1024-768.jpg) 如上图所示,整个表单的数据都放在 FormCore 这一层,同时 FormCore 会暴露一些 API,以便获取、设置、处理数据。Form、Field 组件通过 Sub/Pub 模式与 FormCore 通信,FormCore 通知组件何时重新渲染。表单提供了校验、联动以及结合 Fusion、Antd 三方组件库使用等能力。 ### 竞品对比 **[NoForm](https://github.com/alibaba/nopage)** NoForm 是一个表单操作(比如说校验、提交、联动等)抽象到上层,下层又包装了 Next、Antd 等组件,UI 上的能力较强,也封装了一些常用的布局,但功能能力较弱,用户实现复杂逻辑还是需要写很多代码。 **[Formik](https://github.com/jaredpalmer/formik)**、**[react-final-form](https://github.com/final-form/react-final-form)** 这两个组件有一些共性,都是通过 render props 的方式实现了复杂的状态管理,在性能上也非常地卓越,在社区得到了大量的好评,但在联动上的能力较弱(目前只能更新 value),而且如果要集成 Next 或者 Antd 需要将库的表单组件都封装成 Field,成本较高。 ### 相关链接 - [formik](https://github.com/jaredpalmer/formik) - [react-final-form](https://github.com/final-form/react-final-form) - [noform](https://alibaba.github.io/nopage/#/nopage/noform/brief-intro)