Ant Design 組件提供了Input,InputNumber,Radio,Select,uplod等表單組件,但實際開發中這是不能滿足需求,同時我們希望可以繼續使用Form提供的驗證和提示等方法(使用起來確實很爽),這時需要自己動手封裝一些表單,同時我們還要保持方法可以繼續是使用。
github的代碼地址: https://github.com/haozhaohang/ant-design-expand-component
下面看一下如何自己封裝表單組件,這是一個最基礎的表單使用例子:
1 import React, { PureComponent } from 'react' 2 import { Button, Form, Input, Radio } from 'antd' 3 import FormItem from 'components/FormItem' 4 5 const RadioGroup = Radio.Group 6 const options = [ 7 { label: '男', value: 1 }, 8 { label: '女', value: 2 }, 9 ] 10 11 class Test extends PureComponent { 12 handleSubmit = (e) => { 13 e.preventDefault(); 14 15 const { form: { validateFields } } = this.props; 16 17 validateFields((errors, values) => { 18 if (errors) { 19 return; 20 } 21 console.log(values) 22 }) 23 } 24 25 render() { 26 const { form: { getFieldDecorator } } = this.props 27 28 const nameDecorator = getFieldDecorator('name') 29 const sexDecorator = getFieldDecorator('sex') 30 31 return ( 32 <section> 33 <Form layout="horizontal" onSubmit={this.handleSubmit}> 34 <FormItem label="姓名"> 35 {nameDecorator(<Input />)} 36 </FormItem> 37 38 <FormItem label="年齡"> 39 {sexDecorator(<RadioGroup options={options} />)} 40 </FormItem> 41 42 <FormItem buttonsContainer> 43 <Button type="primary" size="default" htmlType="submit">提交</Button> 44 </FormItem> 45 </Form> 46 </section> 47 ); 48 } 49 } 50 51 export default Form.create()(Test)
現在需求需要我們實現多個姓名的提交,這時使用UI組件提供的表單便無法實現。
下面我們可以封裝一個InputArrary組件:
1 import React, { PureComponent } from 'react' 2 import PropTypes from 'prop-types' 3 import { Button, Icon, Input } from 'antd' 4 5 import './index.scss' 6 7 class InputArray extends PureComponent { 8 constructor(props) { 9 super(props) 10 } 11 12 handleChange = index => { 13 const { value, onChange } = this.props 14 const newValue = [...value] 15 16 newValue[index] = target.value 17 18 onChange(newValue) 19 } 20 21 handleDelete = e => { 22 const target = e.currentTarget 23 const index = target.parentNode.parentNode.firstChild.dataset.index 24 const { value, onChange } = this.props 25 const newValue = [...value] 26 27 newValue.splice(Number(index), 1) 28 29 onChange(newValue) 30 } 31 32 handleAdd = () => { 33 const { value, onChange } = this.props 34 const newValue = [...value, ''] 35 36 onChange(newValue) 37 } 38 39 render() { 40 const { value, ...others } = this.props 41 42 const closeBtn = <Icon type="close-circle" onClick={this.handleDelete} /> 43 44 return ( 45 <div className="input-array-component"> 46 {value.map((v, i) => { 47 return ( 48 <div key={i}> 49 <Input 50 {...others} 51 value={v} 52 suffix={closeBtn} 53 data-index={i} 54 onChange={() => this.handleChange(i)} 55 /> 56 </div> 57 ); 58 })} 59 <div> 60 <Button type="dashed" icon="plus" onClick={this.handleAdd}>添加</Button> 61 </div> 62 </div> 63 ); 64 } 65 } 66 67 InputArray.defaultProps = { 68 value: [] 69 } 70 71 export default InputArray
這是我們就可以像引入Input組件一樣引入InputArray組件實現了一組姓名的提交。
<FormItem label="姓名">
{nameDecorator(<InputArray />)}
</FormItem
組件主要使用的form提供getFieldDecorator方法,這個方法會向組件注入value參數,onChange方法,每次調用onChange方法都會去改變value,從而刷新整個組件。為什么會這樣那,其實Ant Design 會在表單組件外層包裹一層組件,維護一個State值,每次onChange都是在改變外部state值,調用setState來刷新表單組件。
Upload組件使用中也遇到一個坑,Upload組件action上傳地址參數也是必填參數,每次上傳都會直接上傳到服務器,不能和其它表單的數據一起提交,這時候我們也必須從新封裝一個上傳組件,同時因為存在文件或圖片數據就不能使用json格式和后台進行交互,必須使用new FormData()的數據格式上傳,也就是原生的表單的submit提交。
特別注意:
編寫自定義組件時,使用getFieldDecorator過程中,會遇到 (Warning: getFieldDecorator
will override value
, so please don't set value
directly and use setFieldsValue
to set it. )這樣的警告,這是因為我們在自定義組件中定義了value值,getFieldDecorator會覆蓋我們定義的值,需要添加默認值可以使用在getFieldDecorator
的時候,設置initialValue,刪除在自定義組件中定義的value就可以了!可以查看issue#1
github的代碼地址: https://github.com/haozhaohang/ant-design-expand-component