antd表单封装插件
表单可基于antd二次封装(优势:减少代码量,统一管理表单配置,跨组件使用antd的form对象)
import React, {Component} from 'react';
import {
Form,
Row,
Col,
Input,
Button,
Icon,
DatePicker,
Select,
Switch,
InputNumber,
Upload,
Cascader
} from 'antd';
import PropsTypes from 'prop-types';
import provinces from "china-division/dist/provinces.json";
import cities from "china-division/dist/cities.json";
import areas from "china-division/dist/areas.json";
//省市区
areas.forEach(area => {
const matchCity = cities.filter(city => city.code === area.cityCode)[0];
if (matchCity) {
matchCity.children = matchCity.children || [];
matchCity.children.push({
label: area.name,
value: area.name
});
}
});
cities.forEach(city => {
const matchProvince = provinces.filter(
province => province.code === city.provinceCode
)[0];
if (matchProvince) {
matchProvince.children = matchProvince.children || [];
matchProvince.children.push({
label: city.name,
value: city.name,
children: city.children
});
}
});
const options = provinces.map(province => ({
label: province.name,
value: province.name,
children: province.children
}));
const {TextArea} = Input;
const {MonthPicker, RangePicker, WeekPicker} = DatePicker;
const Option = Select.Option;
class SearchArea extends Component {
static propTypes = {
filedList: PropsTypes.array.isRequired,//字段列表
hideExpand: PropsTypes.bool,//是否隐藏收起按钮
formItemLayout: PropsTypes.shape({}),//可以修改表单key和value的布局,具体看antd
};
constructor(props) {
super(props);
this.state = {
expand: true,
expandNum: 5
};
}
//渲染单个字段 根据列表的type返回不同的react元素 TODO:可以在这里进行扩展
getFiledCell = (item) => {
switch (item.type) {
case 'input':
return (<Input className={'wd-170'} allowClear={true} {...item.attr} />);
case 'RangePicker' :
return (<RangePicker allowClear={true} {...item.attr} />);
case 'select':
return (
<Select className={'wd-170_im'} allowClear={true}>
{
item.option.map(temIn => (
<Option key={temIn.key} value={temIn.value}>{temIn.key}</Option>
))
}
</Select>
);
case 'switch' :
return (<Switch {...item.attr} />);
case 'number' :
return (<InputNumber allowClear={true} {...item.attr} />);
case 'textarea' :
return (<TextArea allowClear={true} {...item.attr} />);
case 'mulInput' :
return (
<div style={{display: 'flex'}}>
<Input allowClear={true} {...item.attr} />
<Input allowClear={true} {...item.attr} />
<Input allowClear={true} {...item.attr} />
</div>
);
case 'importFile' :
return (
<Upload {...item.attr}>
<Button>
<Icon type="upload"/> 点击上传
</Button>
</Upload>
);
case 'templateDownload' :
return (
<div>
<a href={item.url}>{item.fileName}</a>
</div>
);
case 'CascadeAddress' :
return (
<Cascader options={options} {...item.attr} />
);
default:
return (<Input allowClear={true} {...item.attr} />);
}
};
getFiledList(filedList) {
const {expand, expandNum} = this.state;
const {form, hideExpand} = this.props;
return filedList.map((item, index) => {
//const count = hideExpand ? 0 : (expand && expandNum);
const {getFieldDecorator} = form;
if(!item.type) {
getFieldDecorator(item.paramName, {
initialValue: item.initialValue
});
return '';
}
return (
<Form.Item label={item.filedName}
key={index.toString()}
style={{ marginRight: "20px"}}>
{getFieldDecorator(item.paramName, {
initialValue: item.initialValue,
rules: item.rules,
})(
this.getFiledCell(item),
)}
</Form.Item>
);
});
}
toggle = () => {
const {expand} = this.state;
this.setState({expand: !expand});
};
handleSearch = () => {
};
handleReset = () => {
};
//默认表单布局
formItemLayout = this.props.formItemLayout || {
labelCol: {
xs: {span: 24},
sm: {span: 8},
},
wrapperCol: {
xs: {span: 24},
sm: {span: 16},
},
};
render() {
const {filedList, hideExpand, onFormInit, form} = this.props;
let {expandNum} = this.state;
onFormInit(form);
return (
<div className="search-area">
{
<Form
className="ant-advanced-search-form"
onSubmit={this.handleSearch}
{...this.formItemLayout}
>
<Row align="middle" type="flex" gutter={24}>
{this.getFiledList(filedList)}
</Row>
{
!hideExpand && filedList.length > expandNum && <Row>
<Col span={24} style={{textAlign: 'right'}}>
<a style={{marginLeft: 8, fontSize: 12}} onClick={this.toggle}>
{this.state.expand ? '展开' : '收起'}
<Icon type={this.state.expand ? 'down' : 'up'}/>
</a>
</Col>
</Row>
}
</Form>
}
</div>
);
}
}
export default Form.create({
name: 'advanced_search',
onValuesChange: (props, value, oldVal) => {
props.onValuesChange && typeof props.onValuesChange === 'function' && props.onValuesChange(value, props.form)
}
})(SearchArea);
外部调用实例
filedList: [
{
filedName: '订单编号',
width: 250,
paramName: 'order_number',
type: 'input'
},
{
filedName: '订单来源',
paramName: 'order_from',
type: 'select',
option: []
},
{
filedName: '配货时间',
paramName: 'pick_time',
type: 'RangePicker',
attr: {
placeholder: ['开始时间', '结束时间'],
style: {
width: 300
}
}
},
{
filedName: '角色名称',
span:24,
paramName: 'role_name',
type: 'input',
initialValue: '',
rules: [
{
required: true,
message: '请输入角色名称',
},
]
},
{
filedName: '角色状态',
span:24,
paramName: 'is_lock',
type: 'switch',
initialValue: 1
}
],//筛选区域表单的配置
onFormInit(form) {
//antd的form对象
form.validateFields(()=>{})
}
<SearchArea onFormInit={this.onFormInit.bind(this)} filedList={filedList}/>