Form 表单

如果项目中使用的是 0.x 版本的基础组件(@icedesign/base, @ali/ice, @alife/next),请在左侧导航顶部切换组件版本。

安装方法

  1. 在命令行中执行以下命令npm install @alifd/next@latest -S

开发指南

何时使用

表单布局、校验、数据提交操作时用到。 组件的设计思想可以看这篇文章 https://zhuanlan.zhihu.com/p/56280821

注意事项

  • 组件不要使用关键字 nodeName 作为 name、id

  • Form 默认使用 size=medium, 并且会控制 FormItem 内所有组件的size。 如果想修改组件的size <FormItem size="small" >

  • 在垂直表单中如果文字(一般 <p> 标签)或者组件向上偏离,可以通过 className="next-form-text-align" 辅助调整

  • 必须是被 <FormItem>直接包裹的组件才能展示校验错误提示。如果界面不展示错误信息,请检查是否有多个层级。 比如 <FormItem><div><Input/></div></FormItem> 是无法展示校验信息的。

API

Form

参数说明类型默认值
inline内联表单Boolean-
size单个 Item 的 size 自定义,优先级高于 Form 的 size, 并且当组件与 Item 一起使用时,组件自身设置 size 属性无效。可选值:'large'(大)'medium'(中)'small'(小)Enum'medium'
labelAlign标签的位置可选值:'top'(上)'left'(左)'inset'(内)Enum'left'
labelTextAlign标签的左右对齐方式可选值:'left'(左)'right'(右)Enum-
fieldnew Field(this) 初始化后,直接传给 Form 即可 用到表单校验则不可忽略此项any-
saveField保存 Form 自动生成的 field 对象签名:Function() => voidFunctionfunc.noop
labelCol控制第一级 Item 的 labelColObject-
wrapperCol控制第一级 Item 的 wrapperColObject-
onSubmitform内有 htmlType="submit" 的元素的时候会触发签名:Function() => voidFunctionfunction preventDefault(e) { e.preventDefault(); }
children子元素any-
value表单数值Object-
onChange表单变化回调签名:Function(values: Object, item: Object) => void参数:values: {Object} 表单数据item: {Object} 详细item.name: {String} 变化的组件名item.value: {String} 变化的数据item.field: {Object} field 实例Functionfunc.noop
component设置标签类型String/Function'form'

Form.Item

手动传递了 wrapCol labelCol 会使用 Grid 辅助布局; labelAlign='top' 会强制禁用 Grid

参数说明类型默认值
labellabel 标签的文本ReactNode-
size单个 Item 的 size 自定义,优先级高于 Form 的 size, 并且当组件与 Item 一起使用时,组件自身设置 size 属性无效。可选值:'large', 'small', 'medium'Enum-
labelCollabel 标签布局,通 <Col> 组件,设置 span offset 值,如 {span: 8, offset: 16},该项仅在垂直表单有效Object-
wrapperCol需要为输入控件设置布局样式时,使用该属性,用法同 labelColObject-
help自定义提示信息,如不设置,则会根据校验规则自动生成.ReactNode-
extra额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。 位于错误信息后面ReactNode-
validateState校验状态,如不设置,则会根据校验规则自动生成可选值:'error'(失败)'success'(成功)'loading'(校验中)Enum-
hasFeedback配合 validateState 属性使用,是否展示 success/loading 的校验状态图标, 目前只有Input支持Booleanfalse
childrennode 或者 function(values)ReactNode/Function-
labelAlign标签的位置可选值:'top'(上)'left'(左)'inset'(内)Enum-
labelTextAlign标签的左右对齐方式可选值:'left'(左)'right'(右)Enum-
required表单校验 不能为空Boolean-
asteriskrequired 的星号是否显示Boolean-
requiredMessagerequired 自定义错误信息String-
requiredTriggerrequired 自定义触发方式String/Array-
min表单校验 最小值Number-
max表单校验 最大值Number-
minmaxMessagemin/max 自定义错误信息String-
minmaxTriggermin/max 自定义触发方式String/Array-
minLength表单校验 字符串最小长度 / 数组最小个数Number-
maxLength表单校验 字符串最大长度 / 数组最大个数Number-
minmaxLengthMessageminLength/maxLength 自定义错误信息String-
minmaxLengthTriggerminLength/maxLength 自定义触发方式String/Array-
length表单校验 字符串精确长度 / 数组精确个数Number-
lengthMessagelength 自定义错误信息String-
lengthTriggerlength 自定义触发方式String/Array-
pattern正则校验any-
patternMessagepattern 自定义错误信息String-
patternTriggerpattern 自定义触发方式String/Array-
format表单校验 四种常用的 pattern可选值:'number', 'email', 'url', 'tel'Enum-
formatMessageformat 自定义错误信息String-
formatTriggerformat 自定义触发方式String/Array-
validator表单校验 自定义校验函数签名:Function() => voidFunction-
validatorTriggervalidator 自定义触发方式String/Array-
autoValidate是否修改数据时自动触发校验Boolean-

Form.Submit

继承 Button API

参数说明类型默认值
onClick点击提交后触发签名:Function(value: Object, errors: Object, field: class) => void参数:value: {Object} 数据errors: {Object} 错误数据field: {class} 实例Functionfunc.noop
validate是否校验/需要校验的 name 数组Boolean/Array-
field自定义 field (在 Form 内不需要设置)Object-

Form.Reset

继承 Button API

参数说明类型默认值
names自定义重置的字段Array-
onClick点击提交后触发签名:Function() => voidFunctionfunc.noop
toDefault返回默认值Boolean-
field自定义 field (在 Form 内不需要设置)Object-

Form.Error

自定义错误展示

参数说明类型默认值
name表单名String/Array-
field自定义 field (在 Form 内不需要设置)Object-
children自定义错误渲染, 可以是 node 或者 function(errors, state)ReactNode/Function-

关于校验

  • 建议一个FormItem放一个组件, 方便错误提示跟随组件展示

  • 组件必须是FormItem的第一层子元素

  • 详细校验请查看 Field 组件文档的 rules

复杂表单场景

如果您的表单场景非常复杂,比如动态渲染,大量字段,复杂数据结构,复杂联动校验,可以考虑使用 uform,uform已经封装了所有fusion组件,保证您开箱即用

代码示例

基本

拉伸浏览器的时候label宽度不变。

如果组件比较靠上,可以用 className="next-form-text-align" 做调整

Form 表单 - 图1

查看源码在线预览

  1. import { Form, Input, Checkbox } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const formItemLayout = {
  4. labelCol: {
  5. fixedSpan: 10
  6. },
  7. wrapperCol: {
  8. span: 14
  9. }
  10. };
  11. class Demo extends React.Component {
  12. handleSubmit = (values) => {
  13. console.log('Get form value:', values);
  14. };
  15. render() {
  16. return (
  17. <Form style={{width: '60%'}} {...formItemLayout} >
  18. <FormItem label="baseUsername:">
  19. <p>Fixed Name</p>
  20. </FormItem>
  21. <FormItem label="password:">
  22. <Input htmlType="password" name="basePass" placeholder="Please Enter Password"/>
  23. </FormItem>
  24. <FormItem label="Note:" help="something">
  25. <Input.TextArea placeholder="something" name="baseRemark" />
  26. </FormItem>
  27. <FormItem label="Agreement:">
  28. <Checkbox name="baseAgreement" defaultChecked>Agree</Checkbox>
  29. </FormItem>
  30. <FormItem label=" ">
  31. <Form.Submit onClick={this.handleSubmit}>Confirm</Form.Submit>
  32. </FormItem>
  33. </Form>
  34. );
  35. }
  36. }
  37. ReactDOM.render(<Demo />, mountNode);

水平

Form 表单 - 图2

查看源码在线预览

  1. import { Form, Input } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. function handleSubmit(v) {
  4. console.log(v);
  5. }
  6. ReactDOM.render(<div>
  7. <Form inline>
  8. <FormItem label="Username:">
  9. <FormItem >
  10. <Input name="first" style={{width: 80}} placeholder="first"/>
  11. </FormItem>
  12. <FormItem >
  13. <Input name="second" style={{width: 80}} placeholder="second"/>
  14. </FormItem>
  15. </FormItem>
  16. <FormItem label="Password:" required hasFeedback={false}>
  17. <Input htmlType="password" name="inlinePass" placeholder="Please enter your password!"/>
  18. </FormItem>
  19. <FormItem label=" ">
  20. <Form.Submit onClick={handleSubmit}>Submit</Form.Submit>
  21. </FormItem>
  22. </Form>
  23. </div>, mountNode);

注册

验证码获取

Form 表单 - 图3

查看源码在线预览

  1. import { Form, Input } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const formItemLayout = {
  4. labelCol: { fixedSpan: 3 },
  5. wrapperCol: { span: 20 }
  6. };
  7. class Demo extends React.Component {
  8. state = {
  9. code: '',
  10. second: 60
  11. }
  12. handleSubmit = (values, errors) => {
  13. if (errors) {
  14. return;
  15. }
  16. console.log('Get form value:', values);
  17. };
  18. sendCode = (values, errors) => {
  19. if (errors) {
  20. return;
  21. }
  22. this.setState({
  23. code: Math.floor(Math.random() * (999999 - 99999 + 1) + 99999)
  24. });
  25. setInterval(() => {
  26. this.setState({
  27. second: --this.state.second
  28. });
  29. }, 1000);
  30. }
  31. render() {
  32. const { code } = this.state;
  33. return (
  34. <Form style={{ width: 400 }} {...formItemLayout} labelTextAlign="left" size="large" labelAlign="inset" >
  35. <FormItem label="name" required asterisk={false}>
  36. <Input name="username" trim defaultValue="frank" />
  37. </FormItem>
  38. <FormItem label="phone" format="tel" required asterisk={false}>
  39. <Input name="phone" trim innerAfter={
  40. <Form.Submit
  41. text
  42. type="primary"
  43. disabled={!!code}
  44. validate={['phone']}
  45. onClick={this.sendCode}
  46. style={{ marginRight: 10 }}
  47. >
  48. {code ? `retry after ${this.state.second}s` : 'send code'}
  49. </Form.Submit>
  50. } />
  51. </FormItem>
  52. {
  53. this.state.code ? <FormItem label="code" required asterisk={false}>
  54. <Input name="code" trim defaultValue={this.state.code} />
  55. </FormItem> : null
  56. }
  57. <FormItem label=" ">
  58. <Form.Submit style={{ width: '100%' }} type="primary" validate onClick={this.handleSubmit}>Submit</Form.Submit>
  59. </FormItem>
  60. </Form>
  61. );
  62. }
  63. }
  64. ReactDOM.render(<Demo />, mountNode);

尺寸

size 会强制设置 FormItem 下的所有组件的size

labelAlign label方位

labelTextAlign 文字左右对齐方式

Form 表单 - 图4

查看源码在线预览

  1. import { Form, Input, Select } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const Option = Select.Option;
  4. const formItemLayout = {
  5. labelCol: {span: 4},
  6. wrapperCol: {span: 20}
  7. };
  8. class Demo extends React.Component {
  9. state = {
  10. size: 'medium'
  11. }
  12. handleChange = (v) => {
  13. this.setState({
  14. size: v
  15. });
  16. }
  17. render() {
  18. return (
  19. <div>
  20. <Form {...formItemLayout} size={this.state.size} style={{maxWidth: '500px'}}>
  21. <FormItem label="Size:">
  22. <Select value={this.state.size} onChange={this.handleChange} style={{width: '100%'}}>
  23. <Option value="small">small</Option>
  24. <Option value="medium">medium</Option>
  25. <Option value="large">large</Option>
  26. </Select>
  27. </FormItem>
  28. <FormItem label="Account:">
  29. <Input placeholder="Please enter your user name" id="userName" name="userName"/>
  30. </FormItem>
  31. <FormItem required label="Password:">
  32. <Input htmlType="password" placeholder="Please enter your password" id="password" name="password"/>
  33. </FormItem>
  34. <FormItem label="Password:" validateState="error">
  35. <Input htmlType="password" placeholder="Check your password" id="rePass" name="rePass"/>
  36. </FormItem>
  37. </Form>
  38. <br/><br/>
  39. <Form size={this.state.size} inline>
  40. <FormItem label="Size:">
  41. <Select style={{width: '100%'}} value={this.state.size} onChange={this.handleChange}>
  42. <Option value="small">small</Option>
  43. <Option value="medium">medium</Option>
  44. <Option value="large">large</Option>
  45. </Select>
  46. </FormItem>
  47. <FormItem label="Account:">
  48. <Input placeholder="Please enter your user name" id="userName2" name="userName2"/>
  49. </FormItem>
  50. <FormItem label="Password:">
  51. <Input htmlType="password" placeholder="Please enter your password" id="password2" name="password2"/>
  52. </FormItem>
  53. <FormItem label="Password:" validateState="error">
  54. <Input htmlType="password" placeholder="Check your password" id="rePass2" name="rePass2"/>
  55. </FormItem>
  56. </Form>
  57. </div>
  58. );
  59. }
  60. }
  61. ReactDOM.render(<Demo />, mountNode);
  1. .demo-ctl {
  2. background-color: #f1f1f1;
  3. padding: 10.0px;
  4. color: #0a7ac3;
  5. border-left: 4.0px solid #0d599a;
  6. }

标签在上

size 会强制设置 FormItem 下的所有组件的size

labelAlign label方位

labelTextAlign 文字左右对齐方式

Form 表单 - 图5

查看源码在线预览

  1. import { Form, Input, Select } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const Option = Select.Option;
  4. class Demo extends React.Component {
  5. render() {
  6. return (
  7. <div>
  8. <Form labelAlign="top" >
  9. <FormItem label="Account:">
  10. <Input placeholder="Please enter your user name" id="userName" name="userName"/>
  11. </FormItem>
  12. <FormItem required label="Password:">
  13. <Input htmlType="password" placeholder="Please enter your password" id="password" name="password"/>
  14. </FormItem>
  15. <FormItem label="Password:" validateState="error">
  16. <Input htmlType="password" placeholder="Please enter your password" id="rePass" name="rePass"/>
  17. </FormItem>
  18. <FormItem label="Size:">
  19. <Select style={{width: '100%'}} name="size">
  20. <Option value="small">small</Option>
  21. <Option value="medium">medium</Option>
  22. <Option value="large">large</Option>
  23. </Select>
  24. </FormItem>
  25. </Form>
  26. <Form inline labelAlign="top">
  27. <FormItem label="Account:">
  28. <Input placeholder="Please enter your user name" id="userName2" name="userName2"/>
  29. </FormItem>
  30. <FormItem label="Password:">
  31. <Input htmlType="password" placeholder="Please enter your password" id="password2" name="password2"/>
  32. </FormItem>
  33. <FormItem label="Password:" validateState="error">
  34. <Input htmlType="password" placeholder="Please enter your password" id="rePass2" name="rePass2"/>
  35. </FormItem>
  36. <FormItem label="Size:">
  37. <Select style={{width: '100%'}} name="size2">
  38. <Option value="small">small</Option>
  39. <Option value="medium">medium</Option>
  40. <Option value="large">large</Option>
  41. </Select>
  42. </FormItem>
  43. </Form>
  44. </div>
  45. );
  46. }
  47. }
  48. ReactDOM.render(<Demo />, mountNode);
  1. .demo-ctl {
  2. background-color: #f1f1f1;
  3. padding: 10.0px;
  4. color: #0a7ac3;
  5. border-left: 4.0px solid #0d599a;
  6. }

标签内嵌

通过设置labelAlign="inset" (只适用于Input、Select组件,其他组件不适用)

Form 表单 - 图6

查看源码在线预览

  1. import { Form, Input, Select } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const Option = Select.Option;
  4. const formItemLayout = {
  5. labelCol: {fixedSpan: 4},
  6. wrapperCol: {span: 20}
  7. };
  8. ReactDOM.render(<div>
  9. <Form {...formItemLayout} labelAlign="inset" style={{maxWidth: '500px'}}>
  10. <FormItem label="User Name:">
  11. <Input placeholder="Please enter your name" id="insetUserName" name="insetUserName"/>
  12. </FormItem>
  13. <FormItem label="Password:" validateState="error">
  14. <Input htmlType="password" placeholder="Please enter your password" id="insetPassword" name="insetPassword"/>
  15. </FormItem>
  16. <FormItem label="Size:">
  17. <Select style={{width: '100%'}}>
  18. <Option value="small">small</Option>
  19. <Option value="medium">medium</Option>
  20. <Option value="large">large</Option>
  21. </Select>
  22. </FormItem>
  23. </Form>
  24. <br/><br/>
  25. <Form labelAlign="inset" inline>
  26. <FormItem label="User Name:">
  27. <Input placeholder="Enter your name" id="insetUserName2" name="insetUserName2"/>
  28. </FormItem>
  29. <FormItem label="Password:" validateState="error" help="Password is required!">
  30. <Input htmlType="password" placeholder="Enter your password" id="insetPassword2" name="insetPassword2"/>
  31. </FormItem>
  32. <FormItem label="Size:">
  33. <Select style={{width: 150}}>
  34. <Option value="small">small</Option>
  35. <Option value="medium">medium</Option>
  36. <Option value="large">large</Option>
  37. </Select>
  38. </FormItem>
  39. </Form>
  40. </div>, mountNode);

嵌套

FormItem 嵌套

Form 表单 - 图7

查看源码在线预览

  1. import { Form, Input, Grid } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const {Row, Col} = Grid;
  4. const formItemLayout = {
  5. labelCol: {span: 4},
  6. wrapperCol: {span: 14}
  7. };
  8. const insetLayout = {
  9. labelCol: {fixedSpan: 3}
  10. };
  11. ReactDOM.render(<Form {...formItemLayout}>
  12. <FormItem id="control-input" label="Input Something:">
  13. <Row gutter="4">
  14. <Col>
  15. <FormItem label="Nest" labelAlign="inset" {...insetLayout} required requiredTrigger="onBlur" asterisk={false}>
  16. <Input placeholder="Please enter..." name="firstname"/>
  17. </FormItem>
  18. </Col>
  19. <Col>
  20. <FormItem label="Nest" labelAlign="inset" {...insetLayout} required asterisk={false}>
  21. <Input placeholder="need onChange" name="secondname" />
  22. </FormItem>
  23. </Col>
  24. </Row>
  25. </FormItem>
  26. <FormItem label="Bank Account:" >
  27. <Row gutter="4">
  28. <Col>
  29. <FormItem required requiredTrigger="onBlur">
  30. <Input name="A"/>
  31. </FormItem>
  32. </Col>
  33. <Col>
  34. <FormItem required requiredTrigger="onBlur">
  35. <Input name="B"/>
  36. </FormItem>
  37. </Col>
  38. <Col>
  39. <FormItem required requiredTrigger="onBlur">
  40. <Input name="C"/>
  41. </FormItem>
  42. </Col>
  43. <Col>
  44. <FormItem required requiredTrigger="onBlur">
  45. <Input name="D"/>
  46. </FormItem>
  47. </Col>
  48. </Row>
  49. </FormItem>
  50. <FormItem label=" ">
  51. <Form.Submit onClick={(v) => console.log(v)}>Submit</Form.Submit>
  52. </FormItem>
  53. </Form>, mountNode);

自定义布局

标签位置:上、左

配合 Row Col 控制表单内元素布局 (注意:FormItem非Form直接子元素需要不能直接直接在Form上设置布局)

Form 表单 - 图8

查看源码在线预览

  1. import { Form, Input, Switch, Grid, Button, Icon, Balloon } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const {Row, Col} = Grid;
  4. const style = {
  5. padding: '20px',
  6. background: '#F7F8FA',
  7. margin: '20px'
  8. };
  9. const formItemLayout = {
  10. labelCol: {fixedSpan: 4}
  11. };
  12. const label = (<span>
  13. name:<Balloon type="primary" trigger={<Icon type="prompt" size="small" />} closable={false}>blablablablablablablabla</Balloon>
  14. </span>);
  15. class Demo extends React.Component {
  16. state = {
  17. labelAlign: 'top'
  18. }
  19. handleChange = (v) => {
  20. this.setState({
  21. labelAlign: v ? 'left' : 'top'
  22. });
  23. }
  24. render() {
  25. const labelAlign = this.state.labelAlign;
  26. return (
  27. <div>
  28. <h3>Label Position</h3>
  29. <Switch checkedChildren="left" unCheckedChildren="top" checked={this.state.labelAlign === 'left'} onChange={this.handleChange} />
  30. <Form style={style}>
  31. <Row gutter="4">
  32. <Col>
  33. <FormItem {...formItemLayout} labelAlign={labelAlign}
  34. label={label}
  35. required
  36. >
  37. <Input placeholder="Enter a search name:"/>
  38. </FormItem>
  39. <FormItem {...formItemLayout} labelAlign={labelAlign}
  40. label="Long search name:"
  41. >
  42. <Input placeholder="Enter a search name:"/>
  43. </FormItem>
  44. <FormItem {...formItemLayout} labelAlign={labelAlign}
  45. label="Search name:"
  46. >
  47. <Input placeholder="Enter a search name:"/>
  48. </FormItem>
  49. </Col>
  50. <Col>
  51. <FormItem {...formItemLayout} labelAlign={labelAlign}
  52. label="Search name:"
  53. >
  54. <Input placeholder="Enter a search name:"/>
  55. </FormItem>
  56. <FormItem {...formItemLayout} labelAlign={labelAlign}
  57. label="Long search name:"
  58. >
  59. <Input placeholder="Enter a search name:"/>
  60. </FormItem>
  61. <FormItem {...formItemLayout} labelAlign={labelAlign}
  62. label="Search name:"
  63. >
  64. <Input placeholder="Enter a search name:"/>
  65. </FormItem>
  66. </Col>
  67. <Col>
  68. <FormItem {...formItemLayout} labelAlign={labelAlign}
  69. label="Search name:"
  70. >
  71. <Input placeholder="Enter a search name:"/>
  72. </FormItem>
  73. <FormItem {...formItemLayout} labelAlign={labelAlign}
  74. label="Long search name:"
  75. >
  76. <Input placeholder="Enter a search name:"/>
  77. </FormItem>
  78. <FormItem {...formItemLayout} labelAlign={labelAlign}
  79. label="Search name:"
  80. >
  81. <Input placeholder="Enter a search name:"/>
  82. </FormItem>
  83. </Col>
  84. </Row>
  85. <Row>
  86. <Col style={{ textAlign: 'right' }}>
  87. <Button type="primary" style={{ marginRight: '5px' }}>Search</Button>
  88. <Button >Clear All</Button>
  89. </Col>
  90. </Row>
  91. </Form>
  92. <Form style={style}>
  93. <Row gutter="4">
  94. <Col>
  95. <FormItem {...formItemLayout} labelAlign={labelAlign}
  96. label={label}
  97. required
  98. >
  99. <Input placeholder="Enter a search name:"/>
  100. </FormItem>
  101. </Col>
  102. <Col>
  103. <FormItem {...formItemLayout} labelAlign={labelAlign}
  104. label="Long search name:"
  105. >
  106. <Input placeholder="Enter a search name:"/>
  107. </FormItem>
  108. </Col>
  109. <Col>
  110. <FormItem {...formItemLayout} labelAlign={labelAlign}
  111. label="Search name:"
  112. >
  113. <Input placeholder="Enter a search name:"/>
  114. </FormItem>
  115. </Col>
  116. <Col>
  117. <FormItem {...formItemLayout} labelAlign={labelAlign}
  118. label="Search name:"
  119. >
  120. <Input placeholder="Enter a search name:"/>
  121. </FormItem>
  122. </Col>
  123. <Col>
  124. <FormItem {...formItemLayout} labelAlign={labelAlign}
  125. label="Search name:"
  126. >
  127. <Input placeholder="Enter a search name:"/>
  128. </FormItem>
  129. </Col>
  130. </Row>
  131. <Row>
  132. <Col style={{ textAlign: 'right' }}>
  133. <Button type="primary" style={{ marginRight: '5px' }}>Search</Button>
  134. <Button >Clear All</Button>
  135. </Col>
  136. </Row>
  137. </Form>
  138. </div>
  139. );
  140. }
  141. }
  142. ReactDOM.render(<Demo />, mountNode);

回车提交

需要Form里面有 htmlType="submit" 的元素

Form 表单 - 图9

查看源码在线预览

  1. import { Form, Input } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. class Demo extends React.Component {
  4. onSubmit(e) {
  5. e.preventDefault(); // form will auto submit if remove this line
  6. console.log('onsubmit');
  7. }
  8. render() {
  9. return (
  10. <Form onSubmit={this.onSubmit.bind(this)}>
  11. <FormItem >
  12. <Input placeholder="Enter Key can also trigger ‘onSubmit’"/>
  13. </FormItem>
  14. <Form.Submit htmlType="submit">submit</Form.Submit>
  15. </Form>
  16. );
  17. }
  18. }
  19. ReactDOM.render(<Demo />, mountNode);

响应式

可以通过配置 labelCol wrapperColGrid.Col 响应式属性实现响应式

Form 表单 - 图10

查看源码在线预览

  1. import { Form, Input, Select } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const formItemLayout = {
  4. labelCol: {xxs: 4, l: 4},
  5. wrapperCol: {xxs: 20, l: 16}
  6. };
  7. ReactDOM.render(<Form {...formItemLayout} >
  8. <FormItem label="userName:">
  9. <Input />
  10. </FormItem>
  11. <FormItem label="password:">
  12. <Input htmlType="password" name="resPass" placeholder="Please Enter Password"/>
  13. </FormItem>
  14. <FormItem label="Country:">
  15. <Select placeholder="Please select a country" style={{width: '100%'}}>
  16. <option value="china">China</option>
  17. <option value="use">United States</option>
  18. <option value="japan">Japan</option>
  19. <option value="korean">South Korea</option>
  20. <option value="Thailand">Thailand</option>
  21. </Select>
  22. </FormItem>
  23. <FormItem label="Note:" help="something">
  24. <Input.TextArea placeholder="something" name="resReremark" />
  25. </FormItem>
  26. <FormItem label=" ">
  27. <Form.Submit>Submit</Form.Submit>
  28. </FormItem>
  29. </Form>, mountNode);

校验提示

<FormItem> 定义 state 属性控制三种校验状态。

如果是 <Input> 组件, 可在<FormItem>上面添加 hasFeedback 控制图标的展示

注意: 反馈图标只对 <Input /> 有效。

Form 表单 - 图11

查看源码在线预览

  1. import { Form, Input, DatePicker, TimePicker, NumberPicker, Select } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const formItemLayout = {
  4. labelCol: {
  5. span: 6
  6. },
  7. wrapperCol: {
  8. span: 14
  9. }
  10. };
  11. ReactDOM.render(
  12. <Form {...formItemLayout}>
  13. <FormItem label="Input Error:" validateState="error" help="Please enter a numeric and alphabetic string">
  14. <Input defaultValue="Invalid choice"/>
  15. </FormItem>
  16. <FormItem label="Loading:" hasFeedback validateState="loading" help="Information Checking...">
  17. <Input defaultValue="Checking"/>
  18. </FormItem>
  19. <FormItem label="Success:" hasFeedback validateState="success">
  20. <Input defaultValue="Successful verification"/>
  21. </FormItem>
  22. <FormItem label="Datepicker:" validateState="error" help="Please select the correct date">
  23. <DatePicker />
  24. </FormItem>
  25. <FormItem label="Timepicker:" validateState="error" help="Please select the correct time">
  26. <TimePicker />
  27. </FormItem>
  28. <FormItem label="Select:" validateState="error" help="Please select a country">
  29. <Select placeholder="Please select a country">
  30. <option value="china">China</option>
  31. <option value="use">United States</option>
  32. <option value="japan">Japan</option>
  33. <option value="korean">South Korea</option>
  34. <option value="Thailand">Thailand</option>
  35. </Select>
  36. </FormItem>
  37. <FormItem label="NumberPicker:" validateState="error">
  38. <NumberPicker defaultValue={0} />
  39. </FormItem>
  40. </Form>
  41. , mountNode);

校验

基本的表单校验例子。

Form 表单 - 图12

查看源码在线预览

  1. import { Form, Input, Radio } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const RadioGroup = Radio.Group;
  4. const formItemLayout = {
  5. labelCol: {
  6. span: 6
  7. },
  8. wrapperCol: {
  9. span: 14
  10. }
  11. };
  12. class BasicDemo extends React.Component {
  13. userExists(rule, value) {
  14. return new Promise((resolve, reject) => {
  15. if (!value) {
  16. resolve();
  17. } else {
  18. setTimeout(() => {
  19. if (value === 'frank') {
  20. reject([new Error('Sorry, this username is already exist.')]);
  21. } else {
  22. resolve();
  23. }
  24. }, 500);
  25. }
  26. });
  27. }
  28. render() {
  29. return (
  30. <Form {...formItemLayout} >
  31. <FormItem
  32. label="Account:"
  33. hasFeedback
  34. validator={this.userExists.bind(this)}
  35. help=""
  36. >
  37. <Input placeholder="Input frank" name="valUsername" />
  38. <Form.Error name="valUsername" >{
  39. (errors, state) => {
  40. if (state === 'loading') {
  41. return 'loading...';
  42. } else {
  43. return errors;
  44. }
  45. }
  46. }</Form.Error>
  47. </FormItem>
  48. <FormItem
  49. label="Email:"
  50. hasFeedback
  51. required
  52. requiredTrigger="onBlur"
  53. format="email"
  54. >
  55. <Input placeholder="Both trigget onBlur and onChange" name="valEmail" />
  56. </FormItem>
  57. <FormItem
  58. label="Password:"
  59. hasFeedback
  60. required
  61. requiredMessage="Please enter password"
  62. >
  63. <Input htmlType="password" name="valPasswd" />
  64. </FormItem>
  65. <FormItem
  66. label="Gender:"
  67. hasFeedback
  68. required
  69. requiredMessage="Please select your gender"
  70. >
  71. <RadioGroup name="valSex" >
  72. <Radio value="male">Male</Radio>
  73. <Radio value="female">Female</Radio>
  74. </RadioGroup>
  75. </FormItem>
  76. <FormItem
  77. label="Remarks:"
  78. required
  79. requiredMessage="Really do not intend to write anything?"
  80. >
  81. <Input.TextArea maxLength={20} hasLimitHint placeholder="Everything is ok!" name="valTextarea" />
  82. </FormItem>
  83. <FormItem wrapperCol={{ offset: 6 }} >
  84. <Form.Submit validate type="primary" onClick={(v, e) => console.log(v, e)} style={{marginRight: 10}}>Submit</Form.Submit>
  85. <Form.Reset >Reset</Form.Reset>
  86. </FormItem>
  87. </Form>
  88. );
  89. }
  90. }
  91. ReactDOM.render(<BasicDemo />, mountNode);

校验

基本的表单校验例子。

Form 表单 - 图13

查看源码在线预览

  1. import { Form, Input, Field } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const formItemLayout = {
  4. labelCol: {
  5. span: 6
  6. },
  7. wrapperCol: {
  8. span: 14
  9. }
  10. };
  11. class BasicDemo extends React.Component {
  12. field = new Field(this);
  13. render() {
  14. const {
  15. field,
  16. field: {
  17. init,
  18. }
  19. } = this;
  20. return (
  21. <Form {...formItemLayout} field={field} >
  22. <Form.Item label="test" key="test2">
  23. <Input {...init('input', {
  24. rules: [{
  25. validator(_rule, value, callback) {
  26. callback(<span>This is a <em>CUSTOM</em> error</span>);
  27. }
  28. }]
  29. })} />
  30. </Form.Item>
  31. <FormItem wrapperCol={{ offset: 6 }} >
  32. <Form.Submit validate type="primary">Submit</Form.Submit>
  33. <Form.Reset >Reset</Form.Reset>
  34. </FormItem>
  35. </Form>
  36. );
  37. }
  38. }
  39. ReactDOM.render(<BasicDemo />, mountNode);

复杂功能(Field))

配合 Field 可以实现较复杂功能

Form 表单 - 图14

查看源码在线预览

  1. import { Form, Input, Radio, Field, Button } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const RadioGroup = Radio.Group;
  4. const formItemLayout = {
  5. labelCol: {
  6. span: 6
  7. },
  8. wrapperCol: {
  9. span: 14
  10. }
  11. };
  12. class BasicDemo extends React.Component {
  13. field = new Field(this);
  14. userExists(rule, value) {
  15. return new Promise((resolve, reject) => {
  16. if (!value) {
  17. resolve();
  18. } else {
  19. setTimeout(() => {
  20. if (value === 'frank') {
  21. reject([new Error('Sorry, this username is already occupied.')]);
  22. } else {
  23. resolve();
  24. }
  25. }, 500);
  26. }
  27. });
  28. }
  29. checkPass(rule, value, callback) {
  30. const { validate } = this.field;
  31. if (value) {
  32. validate(['rePasswd']);
  33. }
  34. callback();
  35. }
  36. checkPass2(rule, value, callback) {
  37. const { getValue } = this.field;
  38. if (value && value !== getValue('passwd')) {
  39. return callback('Inconsistent password input twice!');
  40. } else {
  41. return callback();
  42. }
  43. }
  44. validate = () => {
  45. this.field.validate(['sex']);
  46. }
  47. render() {
  48. const {getState, getValue, getError} = this.field;
  49. return (
  50. <Form {...formItemLayout} field={this.field}>
  51. <FormItem
  52. label="Username:"
  53. hasFeedback
  54. required
  55. validator={this.userExists.bind(this)}
  56. help={getState('username') === 'loading' ? 'Checking ...' : getError('username')}
  57. >
  58. <Input placeholder="Input frank" name="username" />
  59. <p>Hello {getValue('username')}</p>
  60. </FormItem>
  61. <FormItem
  62. label="Password:"
  63. hasFeedback
  64. required
  65. requiredMessage="Please enter password"
  66. validator={this.checkPass.bind(this)}
  67. >
  68. <Input htmlType="password" name="passwd" />
  69. </FormItem>
  70. <FormItem
  71. label="Check your password:"
  72. hasFeedback
  73. required
  74. requiredMessage="Enter your password again"
  75. validator={this.checkPass2.bind(this)}
  76. >
  77. <Input htmlType="password" placeholder="Enter the same password twice" name="rePasswd" />
  78. </FormItem>
  79. <FormItem
  80. label="Gender:"
  81. hasFeedback
  82. required
  83. requiredMessage="Please select your gender"
  84. >
  85. <RadioGroup name="sex" >
  86. <Radio value="male">Male</Radio>
  87. <Radio value="female">Female</Radio>
  88. </RadioGroup>
  89. </FormItem>
  90. <FormItem wrapperCol={{ offset: 6 }} >
  91. <Button onClick={this.validate}>Validate by Field</Button>
  92. <Form.Submit validate type="primary" onClick={(v, e) => console.log(v, e)} style={{margin: '0 10px'}}>Submit</Form.Submit>
  93. <Form.Reset >Reset</Form.Reset>
  94. </FormItem>
  95. </Form>
  96. );
  97. }
  98. }
  99. ReactDOM.render(<BasicDemo />, mountNode);

表单组合

展示和表单相关的其他组件。

Form 表单 - 图15

查看源码在线预览

  1. import { Form, Input, Button, Checkbox, Radio, Select, Range, Balloon, DatePicker, TimePicker, NumberPicker, Field, Switch, Upload, Grid } from '@alifd/next';
  2. const FormItem = Form.Item;
  3. const Option = Select.Option;
  4. const RangePicker = DatePicker.RangePicker;
  5. const {Row, Col} = Grid;
  6. const formItemLayout = {
  7. labelCol: {span: 6},
  8. wrapperCol: {span: 14}
  9. };
  10. class Demo extends React.Component {
  11. field = new Field(this);
  12. handleSubmit(value) {
  13. console.log('Form values:', value);
  14. }
  15. render() {
  16. const init = this.field.init;
  17. return (
  18. <Form {...formItemLayout} field={this.field}>
  19. <FormItem label="I'm the title:">
  20. <p className="next-form-text-align">The quick brown fox jumps over the lazy dog.</p>
  21. <p ><a href="#">Link</a></p>
  22. </FormItem>
  23. <FormItem label="Password:">
  24. <Balloon trigger={<Input htmlType="password" {...init('pass')} />} align="r" closable={false} triggerType="hover">
  25. input password
  26. </Balloon>
  27. </FormItem>
  28. <FormItem label="NumberPicker:">
  29. <NumberPicker min={1} max={10} name="numberPicker" defaultValue={3} />
  30. <span>Something in here</span>
  31. </FormItem>
  32. <FormItem
  33. label="Switch:"
  34. required>
  35. <Switch name="switch" defaultChecked />
  36. </FormItem>
  37. <FormItem label="Range:" required>
  38. <Range defaultValue={30} scales={[0, 100]} marks={[0, 100]} name="range" />
  39. </FormItem>
  40. <FormItem label="Select:" required>
  41. <Select style={{width: 200}} name="select">
  42. <Option value="jack">jack</Option>
  43. <Option value="lucy">lucy</Option>
  44. <Option value="disabled" disabled>disabled</Option>
  45. <Option value="hugohua">hugohua</Option>
  46. </Select>
  47. </FormItem>
  48. <FormItem
  49. label="DatePicker:"
  50. labelCol={{span: 6}}
  51. required>
  52. <Row>
  53. <FormItem style={{marginRight: 10, marginBottom: 0}}><DatePicker name="startDate"/></FormItem>
  54. <FormItem style={{marginBottom: 0}}><DatePicker name="endDate" /></FormItem>
  55. </Row>
  56. </FormItem>
  57. <FormItem
  58. label="RangePicker:"
  59. labelCol={{span: 6}}
  60. required>
  61. <RangePicker name="rangeDate"/>
  62. </FormItem>
  63. <FormItem
  64. label="TimePicker:"
  65. required>
  66. <TimePicker name="time" />
  67. </FormItem>
  68. <FormItem
  69. label="Checkbox:">
  70. <Checkbox.Group name="checkbox">
  71. <Checkbox value="a">option 1 </Checkbox>
  72. <Checkbox value="b">option 2 </Checkbox>
  73. <Checkbox disabled value="c">option 3disabled)</Checkbox>
  74. </Checkbox.Group>
  75. </FormItem>
  76. <FormItem
  77. label="Radio:">
  78. <Radio.Group name="radio">
  79. <Radio value="apple">apple</Radio>
  80. <Radio value="banana">banana</Radio>
  81. <Radio disabled value="cherry">cherrydisabled)</Radio>
  82. </Radio.Group>
  83. </FormItem>
  84. <FormItem
  85. label="Logo:"
  86. >
  87. <Upload action="/upload.do" listType="text" name="upload" >
  88. <Button type="primary" style={{margin: '0 0 10px'}}>Upload</Button>
  89. </Upload>
  90. </FormItem>
  91. <Row style={{marginTop: 24}}>
  92. <Col offset="6">
  93. <Form.Submit type="primary" onClick={this.handleSubmit.bind(this)}>Submit</Form.Submit>
  94. </Col>
  95. </Row>
  96. </Form>
  97. );
  98. }
  99. }
  100. ReactDOM.render(<Demo />, mountNode);

配合redux使用

redux中结合 componentWillReceiveProps setValues 使用, 配合 Field 使用

Form 表单 - 图16

查看源码在线预览

  1. import { Form, Input, Button, Checkbox, Field } from '@alifd/next';
  2. import { combineReducers, createStore } from 'redux';
  3. import { Provider, connect } from 'react-redux';
  4. const CheckboxGroup = Checkbox.Group;
  5. function formReducer(state = {email: '', username: 'xiachi', fruit: ['apple']}, action) {
  6. switch (action.type) {
  7. case 'save_fields':
  8. return {
  9. ...state,
  10. ...action.payload
  11. };
  12. default:
  13. return state;
  14. }
  15. }
  16. class FormDemo extends React.Component {
  17. constructor(props) {
  18. super(props);
  19. this.field = new Field(this, {
  20. onChange: (name, value) => {
  21. console.log('onChange', name, value, this.field.getValues());
  22. this.props.dispatch({
  23. type: 'save_fields',
  24. payload: {
  25. [name]: value
  26. }
  27. });
  28. /* Method 2, Updates all values.
  29. this.props.dispatch({
  30. type: 'save_fields',
  31. payload: this.field.getValues()
  32. });
  33. */
  34. }
  35. });
  36. }
  37. componentWillReceiveProps(nextProps) {
  38. this.field.setValues(nextProps.formData);
  39. }
  40. setEmail() {
  41. this.props.dispatch({
  42. type: 'save_fields',
  43. payload: {
  44. email: 'qq@gmail.com'
  45. }
  46. });
  47. }
  48. setName() {
  49. this.props.dispatch({
  50. type: 'save_fields',
  51. payload: {
  52. username: 'frank'
  53. }
  54. });
  55. }
  56. setGroup() {
  57. this.props.dispatch({
  58. type: 'save_fields',
  59. payload: {
  60. fruit: ['pear']
  61. }
  62. });
  63. }
  64. render() {
  65. return (<Form field={this.field}>
  66. <Form.Item required requiredMessage="required!">
  67. <Input name="email"/>
  68. </Form.Item>
  69. <Form.Item required requiredMessage="required!">
  70. <Input name="username" defaultValue={this.props.formData.username} />
  71. </Form.Item>
  72. <Form.Item required requiredMessage="required!">
  73. <CheckboxGroup name="fruit" dataSource={[{label: 'Apple', value: 'apple'}, {label: 'Pear', value: 'pear'}]} defaultValue={this.props.formData.fruit}/>
  74. </Form.Item>
  75. <p>email: {this.props.email && this.props.email.value}</p>
  76. <Button onClick={this.setEmail.bind(this)}>setEmail</Button>
  77. <Button onClick={this.setName.bind(this)}>setName</Button>
  78. <Button onClick={this.setGroup.bind(this)}>setGroup</Button>
  79. </Form>);
  80. }
  81. }
  82. const ReduxFormDemo = connect((state) => {
  83. return {
  84. formData: state.formReducer
  85. };
  86. })(FormDemo);
  87. const store = createStore(combineReducers({
  88. formReducer
  89. }));
  90. ReactDOM.render(<Provider store={store}>
  91. <div>
  92. <ReduxFormDemo />
  93. </div>
  94. </Provider>, mountNode);

手动设置错误

redux中结合 componentWillReceiveProps setErrors 使用, 配合 Field 使用更加方便

如果需要自己控制错误位置,可以让help="" 然后自己放置展示错误的地方

Form 表单 - 图17

查看源码在线预览

  1. import { Form, Input, Button, Field } from '@alifd/next';
  2. import { combineReducers, createStore } from 'redux';
  3. import { Provider, connect } from 'react-redux';
  4. const initState = {
  5. values: {email: '', username: 'xiachi'},
  6. errors: {}
  7. };
  8. function formReducer(state = initState, action) {
  9. switch (action.type) {
  10. case 'save_fields':
  11. return {
  12. ...state,
  13. values: {
  14. ...state.values,
  15. ...action.values
  16. }
  17. };
  18. case 'set_errors':
  19. return {
  20. ...state,
  21. errors: {
  22. ...state.errors,
  23. ...action.errors
  24. }
  25. };
  26. default:
  27. return state;
  28. }
  29. }
  30. class FormDemo extends React.Component {
  31. constructor(props) {
  32. super(props);
  33. this.field = new Field(this, {
  34. onChange: (name, value) => {
  35. console.log('onChange', name, value, this.field.getError(name));
  36. this.props.dispatch({
  37. type: 'save_fields',
  38. values: {
  39. [name]: value
  40. }
  41. });
  42. this.props.dispatch({
  43. type: 'set_errors',
  44. errors: {
  45. [name]: this.field.getError(name)
  46. }
  47. });
  48. }
  49. });
  50. }
  51. componentWillReceiveProps(nextProps) {
  52. this.field.setValues(nextProps.formData.values);
  53. this.field.setErrors(nextProps.formData.errors);
  54. }
  55. setEmail() {
  56. this.props.dispatch({
  57. type: 'save_fields',
  58. values: {
  59. email: 'qq@gmail.com'
  60. }
  61. });
  62. }
  63. setName() {
  64. this.props.dispatch({
  65. type: 'save_fields',
  66. values: {
  67. username: 'frank'
  68. }
  69. });
  70. }
  71. setError() {
  72. this.props.dispatch({
  73. type: 'set_errors',
  74. errors: {
  75. email: 'Error message from remote'
  76. }
  77. });
  78. }
  79. setErrors() {
  80. this.props.dispatch({
  81. type: 'set_errors',
  82. errors: {
  83. email: 'A-Error message from remote',
  84. username: 'B-Error message from remote'
  85. }
  86. });
  87. }
  88. render() {
  89. return (<Form field={this.field}>
  90. <Form.Item required format="email">
  91. <Input name="email"/>
  92. </Form.Item>
  93. <Form.Item help="" required requiredMessage="required">
  94. <Input name="username" defaultValue={this.props.formData.values.username} />
  95. <p style={{color: 'blue'}}>{this.field.getError('username')}</p>
  96. </Form.Item>
  97. <p>email: {this.props.email && this.props.email.value}</p>
  98. <Button onClick={this.setEmail.bind(this)}>setEmail</Button>
  99. <Button onClick={this.setName.bind(this)}>setName</Button>
  100. <Button onClick={this.setError.bind(this)}>setError</Button>
  101. <Button onClick={this.setErrors.bind(this)}>setErrors</Button>
  102. <Button onClick={() => this.field.reset()}>reset</Button>
  103. </Form>);
  104. }
  105. }
  106. const ReduxFormDemo = connect((state) => {
  107. return {
  108. formData: state.formReducer
  109. };
  110. })(FormDemo);
  111. const store = createStore(combineReducers({
  112. formReducer
  113. }));
  114. ReactDOM.render(<Provider store={store}>
  115. <div>
  116. <ReduxFormDemo />
  117. </div>
  118. </Provider>, mountNode);

无障碍

对于必填项,在组件中要设置aria-required属性,并通过视觉设计上的高亮提示用户。

Form 表单 - 图18

查看源码在线预览

  1. import { Form, Input, Select, Radio, Checkbox, DatePicker, Switch, Upload, Grid, Field } from '@alifd/next';
  2. const RadioGroup = Radio.Group;
  3. const {Row, Col} = Grid;
  4. const FormItem = Form.Item;
  5. const Option = Select.Option;
  6. const formItemLayout = {
  7. labelCol: {
  8. span: 7
  9. },
  10. wrapperCol: {
  11. span: 16
  12. }
  13. };
  14. class Demo extends React.Component {
  15. state = {
  16. size: 'medium'
  17. };
  18. submitHandle = (e) => {
  19. console.log(e);
  20. };
  21. render() {
  22. return (
  23. <div>
  24. <Form {...formItemLayout} size={this.state.size} style={{maxWidth: '800px'}}>
  25. <FormItem required label="username:">
  26. <Input placeholder="Please enter your username" id="a11yUsername" name="a11yUsername" aria-required="true" />
  27. </FormItem>
  28. <FormItem required label="Password:">
  29. <Input htmlType="password" placeholder="Please enter your password" id="a11yPassword" name="a11yPassword" aria-required="true" />
  30. </FormItem>
  31. <FormItem
  32. id="myDateInput-1"
  33. required
  34. label="Accessible Date 1 (YYYY/MM/DD):"
  35. requiredMessage="Please select your date"
  36. >
  37. <DatePicker name="a11yDate" format="YYYY/MM/DD" inputProps={{"aria-required": "true", "id": "myDateInput-1"}}/>
  38. </FormItem>
  39. <FormItem
  40. required
  41. label="Accessible Date 2 (YYYY/MM/DD):"
  42. requiredMessage="Please select your date"
  43. >
  44. <DatePicker name="a11yOtherDate" format="YYYY/MM/DD" dateInputAriaLabel="Date input format YYYY/MM/DD" inputProps={{"aria-required": "true", "aria-label": "Accessible Date 2"}}/>
  45. </FormItem>
  46. <FormItem label="Switch:">
  47. <Switch name="a11ySwitch" aria-label="Accessible Switch" defaultChecked/>
  48. </FormItem>
  49. <FormItem
  50. required
  51. label="gender:"
  52. requiredMessage="Please select your gender"
  53. >
  54. <RadioGroup name="a11ySex">
  55. <Radio value="male" aria-required="true">Male</Radio>
  56. <Radio value="female" aria-required="true">Female</Radio>
  57. </RadioGroup>
  58. </FormItem>
  59. <FormItem label="Language:">
  60. <Checkbox.Group name="a11yLangs" aria-label="Please select a programming language">
  61. <Checkbox value="python">python</Checkbox>
  62. <Checkbox value="java">java</Checkbox>
  63. <Checkbox value="angular">angular</Checkbox>
  64. <Checkbox value="c">c</Checkbox>
  65. <Checkbox value="other">other</Checkbox>
  66. </Checkbox.Group>
  67. </FormItem>
  68. <FormItem label="upload:">
  69. <Upload.Card
  70. listType="card"
  71. action="https://www.easy-mock.com/mock/5b713974309d0d7d107a74a3/alifd/upload"
  72. accept="image/png, image/jpg, image/jpeg, image/gif, image/bmp"
  73. defaultValue={[]}
  74. limit={2}
  75. name="a11yUpload"
  76. />
  77. </FormItem>
  78. <FormItem label="Note:">
  79. <Input.TextArea placeholder="description" name="a11yRemark"/>
  80. </FormItem>
  81. <FormItem wrapperCol={{offset: 5}}>
  82. <Form.Submit validate type="primary" onClick={this.submitHandle} style={{marginRight: 7}}>Submit</Form.Submit>
  83. <Form.Reset style={{marginLeft: 130}}>Reset</Form.Reset>
  84. </FormItem>
  85. </Form>
  86. </div>
  87. );
  88. }
  89. }
  90. ReactDOM.render(<Demo />, mountNode);

相关区块

Form 表单 - 图19

暂无相关区块