IceForm 表单组件
如果项目中使用的是 0.x 版本的基础组件(@icedesign/base, @ali/ice, @alife/next),请在左侧导航顶部切换组件版本。
安装方法
- 在命令行中执行以下命令
npm install @ice/form@0.1.5 -S
表单组件
参数(Props)
参数名 | 说明 | 必填 | 类型 | 默认值 | 备注 |
---|---|---|---|---|---|
initialValues | 表单初始值 | N | object | {} | - |
onSubmit | submit函数 | Y | function | - | - |
onChange | 表单变化回调 | N | function | - | function(values: object, item: object) => void 参数: values: {object} 表单数据 item: {object} 详细 item.name: {string} 变化的组件名 item.value: {string} 变化的数据 |
rules | 校验规则 | N | object | {} | - |
effects | 联动规则 | N | array | [] | - |
layout | 表单布局 | N | object | - | |
renderField | 自定义 Field 布局 | N | function | - | function({label, component, error}) => dom 参数: label: {string/element} Field 的 label component: {string/function} 待渲染的控件 error: {string/element} Field 错误提示信息 |
其他属性比如 style
、className
等均会传递到 form
标签上。
layout
是个对象,包含 4 个属性:
{
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。
<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
是个数组,写法如下:
<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 了,写法如下:
<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:
<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>
codeformCore
formCore
会暴露一些 API,使用这些 API 可以获取、设置表单的数据、状态等。
getFieldValue(name)
:获取某一Field
的值setFieldValue(name, value)
:设置某一Field
的值getValues()
:获取表单的 valuessetValues(values, runEffects)
:设置表单的 values,runEffects 为 Boolean,表示设置 values 之后是否需要执行表单的 effects,默认 falsegetFieldError(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
架构方案
如上图所示,整个表单的数据都放在 FormCore 这一层,同时 FormCore 会暴露一些 API,以便获取、设置、处理数据。Form、Field 组件通过 Sub/Pub 模式与 FormCore 通信,FormCore 通知组件何时重新渲染。表单提供了校验、联动以及结合 Fusion、Antd 三方组件库使用等能力。
竞品对比
NoForm 是一个表单操作(比如说校验、提交、联动等)抽象到上层,下层又包装了 Next、Antd 等组件,UI 上的能力较强,也封装了一些常用的布局,但功能能力较弱,用户实现复杂逻辑还是需要写很多代码。
这两个组件有一些共性,都是通过 render props 的方式实现了复杂的状态管理,在性能上也非常地卓越,在社区得到了大量的好评,但在联动上的能力较弱(目前只能更新 value),而且如果要集成 Next 或者 Antd 需要将库的表单组件都封装成 Field,成本较高。
相关链接
代码示例
Form
的基本用法
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input, Switch, Select, Checkbox } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const Option = Select.Option;
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
onChange(values, field) {
console.log(values, field);
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
onChange={this.onChange}
initialValues={{
username: 'icer',
age: 3,
intro: '让前端开发简单而友好'
}}
>
<h2>个人资料</h2>
<Field label="姓名:" name="username" component={Input} placeholder="请输入名字" />
<Field label="年龄:" name="age" component={Input} htmlType="number" placeholder="请输入年龄" />
<Field label="简介:" name="intro" component={Input.TextArea} placeholder="请简单介绍一下自己的工作经历" />
<Field label="开关:" name="open" component={Switch} valueName="checked" />
<Field label="尺寸:" name="size" component={Select} value="medium" placeholder="请选择尺寸">
<Option value="small" key="small">小</Option>
<Option value="medium" key="medium">中</Option>
<Option value="large" key="large">大</Option>
</Field>
<Field label="选项:" name="checkbox" value={['b']} component={Checkbox.Group}>
<Checkbox value="a">选项一</Checkbox>
<Checkbox value="b">选项二</Checkbox>
<Checkbox disabled value="c">选项三(disabled)</Checkbox>
</Field>
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
Form
子组件使用 function
渲染时,可以调用 FormCore
中的 API
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
const initialValues = {
username: 'icer',
age: 3,
intro: '让前端开发简单而友好'
};
return (
<div>
<Form
onSubmit={this.onSubmit}
initialValues={initialValues}
>
{formCore => (
<div>
<h2>个人资料</h2>
<Field label="姓名:" name="username" component={Input} placeholder="请输入名字" />
<Field label="年龄:" name="age" component={Input} htmlType="number" placeholder="请输入年龄" />
<Field label="简介:" name="intro" component={Input.TextArea} placeholder="请简单介绍一下自己的工作经历" />
<Field label="">
<div>
<Button htmlType="submit" style={{marginRight: '20px'}}>Submit</Button>
<Button onClick={() => formCore.reset()}>Reset</Button>
</div>
</Field>
</div>
)}
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
校验规则可以写在 Form
属性上或者 Field
属性上
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
rules={{
username: [{
required: true,
min: 5,
message: '姓名至少5个字符'
}]
}}
>
<h2>个人资料</h2>
<Field label="姓名:" name="username" component={Input} placeholder="请输入名字" placeholder="请输入名字"/>
<Field label="年龄:" name="age" component={Input} htmlType="number" placeholder="请输入年龄" rules={[{
message: '年龄必填且大于18岁',
required: true,
validator: (rule, value) => value > 18
}]} />
<Field label="简介:" name="intro" component={Input.TextArea} placeholder="请简单介绍一下自己的工作经历" />
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
异步校验,校验结果的 message
直接 callback
即可
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form onSubmit={this.onSubmit}>
<h2>个人资料</h2>
<Field name="name" label="名称:" component={Input} autoComplete="off" placeholder="请输入名字" rules={{
async asyncValidator(rule, value, callback) {
if (!value) {
callback('名称必填');
} else {
await sleep(500);
if (~['john', 'paul', 'george', 'ringo'].indexOf(value)) {
callback('名称已存在');
} else {
callback(undefined)
}
}
}
}} />
<Field label="年龄:" name="age" component={Input} htmlType="number" placeholder="请输入年龄" rules={[{
message: '年龄必填且大于18岁',
required: true,
validator: (rule, value) => value > 18
}]} />
<Field label="简介:" name="intro" component={Input.TextArea} placeholder="请简单介绍一下自己的工作经历" />
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
基础联动
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input, Radio } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
rules={{
username: [{
required: true,
min: 5,
message: '姓名至少5个字符'
}],
age: [{
required: true,
message: '大于18岁',
validator: (rule, value) => value > 18
}]
}}
effects={[
{
field: 'username',
handler: formCore => {
const name = formCore.getFieldValue('username');
if (name === 'Khaleesi') {
formCore.setFieldValue('age', 28)
}
}
},
{
field: 'gender',
handler: formCore => {
const gender = formCore.getFieldValue('gender');
if (gender === 'female') {
formCore.setFieldProps('age', {
visible: false,
});
} else {
formCore.setFieldProps('age', {
visible: true,
});
}
}
}
]}
>
<h2>个人资料</h2>
<Field label="姓名:" name="username" component={Input} placeholder="请输入名字" />
<Field label="性别:" name="gender" component={Radio.Group}>
<Radio value="male">男</Radio>
<Radio value="female">女</Radio>
<Radio value="x">X</Radio>
</Field>
<Field label="年龄:" name="age" component={Input} htmlType="number" placeholder="请输入年龄" />
<Field label="简介:" name="intro" component={Input.TextArea} placeholder="请简单介绍一下自己的工作经历" />
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
省市联动
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Input, Button, Select } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const provinceData = ['Zhejiang', 'Hubei', 'Jiangsu'];
const cityData = {
Zhejiang: ['Hangzhou', 'Ningbo', 'Wenzhou'],
Hubei: ['Wuhan', 'Yichang', 'Jingzhou'],
Jiangsu: ['Nanjing', 'Suzhou', 'Zhenjiang']
};
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
effects={[
{
field: 'province',
handler: formCore => {
const province = formCore.getFieldValue('province')
formCore.setValues({
city: '',
population: 0
})
formCore.setFieldProps('city', {dataSource: cityData[province]})
}
},
{
field: 'city',
handler: formCore => {
const city = formCore.getFieldValue('city')
if (city === 'Suzhou') {
formCore.setFieldProps('population', {disabled: true})
formCore.setFieldValue('population', 0)
} else {
formCore.setFieldProps('population', {disabled: false})
}
}
}
]}
>
<div style={{
marginBottom: 20,
}}>当城市为“苏州”,则 disabled 人口</div>
<Field label="省:" layout={{wrapperCol: 2}} name="province" placeholder="Select Province" dataSource={provinceData} component={Select} />
<Field label="市:" layout={{wrapperCol: 2}} name="city" placeholder="Select City" dataSource={[]} component={Select} />
<Field label="人口:" name="population" placeholder="The population of the city" component={Input} htmlType="number" />
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
同时监听两个 Field
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
effects={[
{
field: 'number1',
handler: formCore => {
const value1 = formCore.getFieldValue('number1');
const value2 = formCore.getFieldValue('number2');
if (Number(value1) < Number(value2)) {
formCore.setFieldError('number2', 'number1不能小于number2');
} else {
formCore.setFieldError('number2', undefined);
}
}
},
{
field: 'number2',
handler: formCore => {
const value1 = formCore.getFieldValue('number1');
const value2 = formCore.getFieldValue('number2');
if (Number(value1) < Number(value2)) {
formCore.setFieldError('number2', 'number1不能小于number2');
} else {
formCore.setFieldError('number2', undefined);
}
}
}
]}
>
<Field label="Number1:" name="number1" component={Input} htmlType="number" placeholder="number1 必须大于等于 number2" />
<Field label="Number2:" name="number2" component={Input} htmlType="number" placeholder="number2 必须小于等于 number1" />
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
通过 Form 的 renderField 自定义 Field 布局
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
renderField={({label, component, error}) => (
<div style={{marginBottom: '10px'}}>
<div>{label}</div>
<span>{component}</span>
<span style={{color: '#ee7893'}}>{error}</span>
</div>
)}
rules={{
username: [{
required: true,
min: 5,
message: '姓名至少5个字符'
}]
}}
>
<Field label="姓名:" name="username" component={Input} placeholder="请输入名字" />
<Field label="年龄:" name="age" component={Input} htmlType="number" placeholder="请输入年龄" />
<Button htmlType="submit">Submit</Button>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
Format Feild's value
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, DatePicker, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form onSubmit={this.onSubmit}>
<h4>姓名显示、存储均为小写,日期存储格式为时间戳</h4>
<Field name="name" label="姓名:" component={Input} placeholder="请输入姓名" setValueFormatter={
value => value && value.toLowerCase()
} getValueFormatter={
value => value && value.toLowerCase()
} />
<Field label="生日:" name="date" component={DatePicker} getValueFormatter={
value => Date.parse(value)
} />
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
const Address = ({ name, label }) => (
<React.Fragment>
<div>
<Field
name={`${name}.street`}
component={Input}
label={`${label} Street:`}
placeholder={`${label} Street`}
/>
</div>
<div>
<Field
name={`${name}.city`}
label={`${label} City:`}
component={Input}
placeholder={`${label} City`}
/>
</div>
<div>
<Field
name={`${name}.postalCode`}
label={`${label} Postal Code:`}
component={Input}
placeholder={`${label} Postal Code`}
/>
</div>
</React.Fragment>
)
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form onSubmit={this.onSubmit}>
<h1>可复用的 Field Group</h1>
<Address name="billing" label="Billing" />
<Address name="shipping" label="Shipping" />
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
异步加载数据进行首屏渲染
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const load = async () => {
await sleep(2000);
return {
name: 'erikras',
age: 20,
desc: '我是 erikras'
};
}
class App extends Component {
state = { data: {} }
async componentDidMount() {
this.setState({ loading: true });
const data = await load();
this.setState({ loading: false, data });
}
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
const Age = (<span style={{color: 'green'}}>年龄:</span>);
return (
<div>
<h2>加载表单数据并且初始化(label支持自定义jsx)</h2>
<Form
initialValues={this.state.data}
onSubmit={this.onSubmit}
effects={[{
field: 'name',
handler: formCore => {
const name = formCore.getFieldValue('name');
if (name === 'erikras') {
formCore.setFieldValue('age', 28)
}
}
}]}
>
{this.state.loading && <div className="loading">loading...</div>}
<Field name="name" label={<span style={{color: 'red'}}>名称:</span>} component={Input} placeholder="请输入名字" />
<Field name="age" label={Age} component={Input} placeholder="请输入年龄" />
<Field name="desc" label="简介:" component={Input.TextArea} placeholder="请简单介绍一下自己的工作经历" />
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
Form 结合对话框
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Input, Button, Dialog, Switch } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
handleSubmit = null;
state = {
visible: false
};
onOpen = () => {
this.setState({
visible: true
});
};
onClose = reason => {
this.setState({
visible: false
});
};
onOk = (e) => {
this.handleSubmit(e);
};
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Button onClick={this.onOpen} type="primary">
Open dialog
</Button>
<Dialog
title="表单 Form 对话框"
visible={this.state.visible}
onOk={this.onOk.bind(this)}
onCancel={this.onClose.bind(this, 'cancelClick')}
onClose={this.onClose}
style={{
width: 600,
}}
>
<Form
onSubmit={this.onSubmit}
layout={{
labelCol: 4,
wrapperCol: 8
}}
>
{formCore => {
this.handleSubmit = formCore.submit.bind(formCore);
return (
<div>
<Field name="name" label="名称:" component={Input} placeholder="请输入名字" />
<Field name="age" label="年龄:" component={Input} placeholder="请输入年龄" />
<Field name="desc" label="简介:" component={Input.TextArea} placeholder="请简单介绍一下自己的工作经历" />
<Field name="open" label="是否打开:" component={Switch} valueName="checked" value={true} />
<Field name="openDesc" label="打开时的描述:" component={Input} placeholder="description when opening"/>
<Field name="closeDesc" label="关闭时的描述:" component={Input} placeholder="description when closing" />
</div>
)
}}
</Form>
</Dialog>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
使用原生 html 标签
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
rules={{
username: [{
required: true,
min: 5,
message: '姓名至少5个字符'
}]
}}
>
<h2>个人资料</h2>
<Field label="姓名:" name="username" component="input" placeholder="请输入名字" />
<Field label="年龄:" name="age" component="input" type="number" placeholder="请输入年龄" />
<Field label="简介:" name="intro" component="textarea" placeholder="请简单介绍一下自己的工作经历" />
<Field label="框架:" name="framework" component="select" value="react">
<option value="vue">Vue</option>
<option value="react">React</option>
<option value="angular">Angular</option>
</Field>
<Field label="ICE背景:" name="ice" component="input" valueName='checked' value={false} type="radio" />
<Field label="">
<button type="submit">Submit</button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
state = {
renderField: undefined,
data: {},
rules: {
username: [{
required: true,
min: 5,
message: '姓名至少5个字符'
}]
}
}
async componentDidMount() {
await sleep(1000);
this.setState({
renderField: ({label, component, error}) => (
<div style={{marginBottom: '15px'}}>
<div>{label}</div>
<span>{component}</span>
<span style={{marginLeft: '10px', color: '#ee7893'}}>{error}</span>
</div>
),
data: {
username: 'erikras',
age: 20,
desc: '我是 erikras'
},
rules: {
username: [{
required: true,
min: 10,
message: '姓名至少10个字符'
}]
}
})
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
initialValues={this.state.data}
renderField={this.state.renderField}
rules={this.state.rules}
>
<Field label="姓名:" name="username" component={Input} placeholder="请输入名字" />
<Field label="年龄:" name="age" component={Input} htmlType="number" placeholder="请输入年龄" />
<Field label="简介: " name="desc" component={Input.TextArea} placeholder="请简单介绍一下自己的工作经历" />
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
表单布局
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
const layout = {
labelCol: 2,
wrapperCol: 4,
labelTextAlign: 'left',
labelAlign: 'top'
};
return (
<div>
<Form
layout = {layout}
onSubmit={this.onSubmit}
rules={{
username: [{
required: true,
min: 5,
message: '姓名至少5个字符'
}]
}}
>
<h2>个人资料</h2>
<Field label="姓名:" name="username" component={Input} placeholder="请输入名字" errorRender={
error => <span style={{color: '#ff7000'}}>{error}</span>
} />
<Field label="年龄:" name="age" component={Input} tips="身份证上的年龄" placeholder="请输入年龄" />
<Field label="简介:" name="intro" component={Input.TextArea} placeholder="请简单介绍一下自己的工作经历" tips="介绍自己的经历介绍自己的经历介绍自己的经历介绍自己的经历" />
<Field label="" name="submit">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
标签布局,当前支持 labelTextAlign 和 labelAlign
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
class App extends Component {
render() {
return (
<div>
<Form
layout = {{
labelTextAlign: 'left'
}}
>
<h2>标签靠左(labelTextAlign: left)</h2>
<Field label="name: " name="name" component={Input} placeholder="please input name" />
<Field label="age: " name="age" component={Input} placeholder="please input age" />
<Field label="intro: " name="intro" component={Input} placeholder="please input intro" />
</Form>
<Form
layout = {{
labelTextAlign: 'right'
}}
>
<h2>标签靠右(labelTextAlign: right)</h2>
<Field label="name: " name="name" component={Input} placeholder="please input name" />
<Field label="age: " name="age" component={Input} placeholder="please input age" />
<Field label="intro: " name="intro" component={Input} placeholder="please input intro" />
</Form>
<Form
layout = {{
labelAlign: 'top',
labelTextAlign: 'left'
}}
>
<h2>标签在上面(labelAlign: top)</h2>
<Field label="name: " name="name" component={Input} placeholder="please input name" />
<Field label="age: " name="age" component={Input} placeholder="please input age" />
<Field label="intro: " name="intro" component={Input} placeholder="please input intro" />
</Form>
<Form
layout = {{
labelAlign: 'left'
}}
>
<h2>标签在左边(labelAlign: left)</h2>
<Field label="name: " name="name" component={Input} placeholder="please input name" />
<Field label="age: " name="age" component={Input} placeholder="please input age" />
<Field label="intro: " name="intro" component={Input} placeholder="please input intro" />
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
Form
自定义标签,给每个标签增加必填符号
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input, Switch, Select, Checkbox } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const Option = Select.Option;
function renderLabel(name) {
return (
<span>
<span style={{
color: 'red',
}}>*</span>
{name}
</span>
);
}
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
rules={{
username: [{
required: true,
min: 5,
message: '姓名至少5个字符'
}],
age: [{
required: true,
message: '年纪必填'
}],
intro: [{
required: true,
message: '简介必填'
}],
}}
>
<h2>个人资料</h2>
<Field label={renderLabel('姓名:')} name="username" component={Input} placeholder="请输入名字" />
<Field label={renderLabel('年龄:')} name="age" component={Input} htmlType="number" placeholder="请输入年龄" />
<Field label={renderLabel('简介:')} name="intro" component={Input.TextArea} placeholder="请简单介绍一下自己的工作经历"/>
<Field label="开关:" name="open" component={Switch} />
<Field label="尺寸:" name="size" component={Select} placeholder="请选择尺寸">
<Option value="small" key="small">小</Option>
<Option value="medium" key="medium">中</Option>
<Option value="large" key="large">大</Option>
</Field>
<Field label="选项:" name="checkbox" component={Checkbox.Group}>
<Checkbox value="a">选项一</Checkbox>
<Checkbox value="b">选项二</Checkbox>
<Checkbox disabled value="c">选项三(disabled)</Checkbox>
</Field>
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input, Switch, Select, Checkbox } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const Option = Select.Option;
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
className="ice-inline-form"
>
<h2>个人资料</h2>
<div className="field-wrapper">
<Field label="姓名:" name="username" component={Input} placeholder="请输入姓名" />
<Field label="年龄:" name="age" component={Input} htmlType="number" placeholder="请输入年龄" />
<Field label="地址:" name="address" component={Input} placeholder="请输入地址" />
<Field label="手机:" name="tel" component={Input} htmlType="number" placeholder="请输入手机号码" />
<Field label="邮件:" name="email" component={Input} placeholder="请输入邮件地址" />
</div>
<Button className="btn" htmlType="submit">Submit</Button>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
.ice-inline-form .field-wrapper {
display: flex;
flex-wrap: wrap;
}
.ice-inline-form .ice-field {
width: 50%;
height: 40px;
}
.ice-inline-form .field-wrapper {
overflow: hidden;
background-color: #ddd;
padding-top: 15px;
padding-bottom: 15px;
}
.ice-inline-form .btn {
margin-top: 20px;
}
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input, Switch, Select, Checkbox } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const Option = Select.Option;
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
layout={{
labelTextAlign: 'left'
}}
className="ice-first-inline-form"
>
<h2>个人资料</h2>
<div style={{display: 'flex'}}>
<Field style={{flexBasis: '35%'}} label="姓名:" name="username" component={Input} placeholder="请输入姓名" />
<Field style={{flexBasis: '30%'}} label="年龄:" name="age" component={Input} htmlType="number" placeholder="请输入年龄" />
</div>
<Field label="地址:" name="address" component={Input} placeholder="请输入地址" />
<Field label="手机:" name="tel" component={Input} htmlType="number" placeholder="请输入手机号码" />
<Field label="邮件:" name="email" component={Input} placeholder="请输入邮件地址" />
<Button style={{marginLeft: '60px', marginTop: '15px'}} className="btn" htmlType="submit">Submit</Button>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
.ice-first-inline-form .ice-field .ice-field-label {
display: inline;
width: auto ;
}
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, FieldArray, Field } from '@ice/form';
import { Button, Input, DatePicker } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
>
<h2>新增顾客名单</h2>
<FieldArray label="新增顾客:" name="customers">
<Field className="field-array-item" name="customer0" component={Input} placeholder="请输入顾客的名字" />
<Field className="field-array-item" name="customer1" component={Input} placeholder="请输入顾客的名字" />
<Field className="field-array-item" name="customer2" component={Input} placeholder="请输入顾客的名字" />
</FieldArray>
<Field label="日期:" name="date" component={DatePicker} />
<Field label="">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
.field-array-item [class*='ice-col-'] {
padding-top: 0;
padding-left: 0;
}
Fusion 表单组件
查看源码在线预览
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import { Button, Input, NumberPicker, Switch, Range, Select, DatePicker, TimePicker, Checkbox, Radio } from '@alifd/next';
const Option = Select.Option;
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<Form
onSubmit={this.onSubmit}
>
<Field label="Password:" name="password" htmlType="password" component={Input} placeholder="请输入密码" />
<Field label="NumberPicker:" name="numberPicker" defaultValue={3} component={NumberPicker} />
<Field label="Switch:" name="switch" component={Switch} valueName="checked" value={false} />
<Field label="Range:" name="range" defaultValue={30} scales={[0, 100]} marks={[0, 100]} component={Range} />
<Field label="Select:" name="select" component={Select} defaultValue='lucy'>
<Option value="jack">jack</Option>
<Option value="lucy">lucy</Option>
<Option value="disabled" disabled>disabled</Option>
<Option value="hugohua">hugohua</Option>
</Field>
<Field label="DatePicker:" name="date" component={DatePicker} />
<Field label="TimePicker:" name="time" component={TimePicker} />
<Field label="Checkbox:" name="checkbox" defaultValue={[]} component={Checkbox.Group}>
<Checkbox value="a">option 1 </Checkbox>
<Checkbox value="b">option 2 </Checkbox>
<Checkbox disabled value="c">option 3(disabled)</Checkbox>
</Field>
<Field label="Radio:" name="radio" component={Radio.Group}>
<Radio value="apple">apple</Radio>
<Radio value="banana">banana</Radio>
<Radio disabled value="cherry">cherry(disabled)</Radio>
</Field>
<Field label="" name="submit">
<Button htmlType="submit">Submit</Button>
</Field>
</Form>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);