FormGroup 三种模式,mode

  1. form,纯表单,没有提交按钮,应用场景
    1. 弹窗里面嵌套
    2. 表单分组
  2. submit,提交表单
  3. search 搜索,和 Table搭配使用

表单校验

  1. async function onFinish(){
  2. // 校验表单通过后,才会获取到值
  3. const values = await form.validateFields();
  4. // 直接获取值,不校验表单
  5. const values = await formRef.current.getFieldsValue();
  6. }

手动设置表单错误

  1. form.setFieldsValue({
  2. // '表单字段name': '值',
  3. id: '4c6ee816'
  4. });
  5. form.current.setFields([
  6. // { name: '表单字段name', value: '需要设置的值', errors: ['错误信息'] }, 当 errors 为非空数组时,表单项呈现红色,
  7. { name: 'id', value: '123', errors: ['error message'] }
  8. ]);

高级搜索表单参考
https://ant-design.antgroup.com/components/form-cn#components-form-demo-advanced-search

  1. <FormGroup
  2. fields={fields}
  3. col={24}
  4. style={{width: '50%'}}
  5. okButtonProps={{
  6. children: '提交',
  7. }}
  8. cancelButtonProps={{
  9. children: '取消',
  10. }}
  11. confirmLoading={false}
  12. mode='form'
  13. />

FormGroup

  1. import React, { useState, forwardRef, useImperativeHandle } from 'react';
  2. import { func, object, array, number } from 'prop-types';
  3. import { Form, Row, Col, Space, Button } from 'antd';
  4. import ItemField from './ItemField';
  5. import IconExpand from './IconExpand';
  6. export function labelCol(col = 5) {
  7. return {
  8. labelCol: { span: col },
  9. wrapperCol: { span: 24 - col },
  10. };
  11. }
  12. const { Item } = Form;
  13. const fields = [
  14. {
  15. name: 'level',
  16. label: '等级',
  17. component: Checkbox.Group,
  18. initialValue: 'a',
  19. props: {
  20. options: [{key: 'AA', value: 'a'}].map(key => {
  21. return { label: <Tag level={key} />, value: key };
  22. }),
  23. className: 'small',
  24. },
  25. },
  26. {
  27. name: 'code',
  28. label: '状态',
  29. component: Select,
  30. props: {
  31. options: [],
  32. mode: 'multiple',
  33. placeholder: `${PLACEHOLDER.select}`,
  34. valueKey: 'label'
  35. },
  36. },
  37. { name: 'title', label: '事件名称' },
  38. {
  39. name: 'time',
  40. label: '创建时间',
  41. component: DatePicker,
  42. props: {
  43. className: 'full',
  44. placeholder: `${PLACEHOLDER.select}时间`,
  45. },
  46. },
  47. {
  48. name: 'user',
  49. label: '用户',
  50. component: Select,
  51. // 组件的 props
  52. props: {
  53. url: '/api/v1/users',
  54. mode: 'tags',
  55. },
  56. },
  57. ];
  58. const FormRef = forwardRef(FormGroup);
  59. FormRef.propTypes = {
  60. fields: array.isRequired,
  61. onChange: func,
  62. total: number,
  63. span: number,
  64. };
  65. FormRef.defaultProps = {
  66. onChange: () => {},
  67. total: 3,
  68. span: 8,
  69. };
  70. export default FormRef;
  71. function FormGroup(props, ref) {
  72. const {fields, onChange, total, span } = props;
  73. const [form] = Form.useForm();
  74. const [expand, setExpand] = useState(false);
  75. // const nameValue = Form.useWatch('name', form);
  76. useImperativeHandle(ref, () => form);
  77. return (
  78. <Form
  79. {...labelCol(6)}
  80. form={form}
  81. onValuesChange={onChange}
  82. >
  83. <Row gutter={24}>
  84. <ItemField
  85. fields={fields}
  86. expand={expand}
  87. total={total}
  88. />
  89. <Col span={span}>
  90. <Item wrapperCol={{ offset: 4 }}>
  91. <Space>
  92. <Button type="primary" htmlType="submit">
  93. 查询
  94. </Button>
  95. <Button onClick={() => form.resetFields() }>
  96. 重置
  97. </Button>
  98. <IconExpand
  99. expand={expand}
  100. setExpand={setExpand}
  101. />
  102. </Space>
  103. </Item>
  104. </Col>
  105. </Row>
  106. </Form>
  107. );
  108. }

ItemField

  1. import React, { useMemo } from 'react';
  2. import { array, bool, number } from 'prop-types';
  3. import { Col, Form } from 'antd';
  4. import ItemComponent from './ItemComponent';
  5. const { Item } = Form;
  6. ItemField.propTypes = {
  7. fields: array.isRequired,
  8. total: number.isRequired,
  9. expand: bool.isRequired,
  10. col: number.isRequired,
  11. };
  12. function ItemField({ fields, total, expand, col, isSearch }) {
  13. // 初始化显示多少个表单
  14. const source = useMemo(() => {
  15. if (!isSearch) return fields;
  16. const { length } = fields;
  17. return fields.slice(0, expand ? length : total)
  18. }, [fields, expand, total, isSearch ]);
  19. const children = [];
  20. for (const [index, item] of source.entries()) {
  21. const { span = 8, label, name, rules, component, props } = item;
  22. const itemElement = (
  23. <Col span={col || span} key={index}>
  24. <Item
  25. label={label}
  26. name={name}
  27. rules={rules}
  28. >
  29. <ItemComponent
  30. component={component}
  31. props={props}
  32. label={label}
  33. />
  34. </Item>
  35. </Col>
  36. );
  37. children.push(itemElement);
  38. }
  39. return children;
  40. }
  41. export default ItemField

ItemComponent

  1. import React, {
  2. createElement,
  3. // 是不是有效的 ReactElement
  4. isValidElement,
  5. } from 'react';
  6. import {
  7. Button,
  8. Input,
  9. InputNumber,
  10. DatePicker,
  11. Checkbox,
  12. Radio,
  13. Switch,
  14. Select,
  15. AutoComplete,
  16. } from 'antd';
  17. import { isObject, isFunction } from 'lodash';
  18. const { TextArea, Password } = Input;
  19. const { RangePicker } = DatePicker;
  20. export const PLACEHOLDER = {
  21. input: '请输入',
  22. select: '请选择',
  23. };
  24. // 表单组件
  25. const COMPONENTS = {
  26. AutoComplete,
  27. Button,
  28. Checkbox,
  29. CheckboxGroup: Checkbox.Group,
  30. DatePicker,
  31. Input,
  32. InputNumber,
  33. Password,
  34. TextArea,
  35. RadioGroup: Radio.Group,
  36. Switch,
  37. Select,
  38. RangePicker,
  39. };
  40. // 不要忽略 rest的 value, onChange参数
  41. function ItemComponent({ component, props, label, ...rest }) {
  42. // 默认组件 component = Input
  43. let Component = Input;
  44. // 如果是 React组件
  45. if (isValidElement(component) || isFunction(component)) {
  46. Component = component
  47. }
  48. // component 是字符串
  49. else if (COMPONENTS[component]) {
  50. Component = COMPONENTS[component];
  51. }
  52. // 动态创建表单
  53. const defaultProps = isObject(props)
  54. ? props
  55. : { placeholder: `${PLACEHOLDER.input}${label}` };
  56. return createElement(Component, {
  57. ...defaultProps,
  58. ...rest,
  59. });
  60. }
  61. export default ItemComponent

IconExpand

切换上下箭头

  1. import React, { useState } from 'react';
  2. import { DownOutlined, UpOutlined } from '@ant-design/icons';
  3. export function IconExpand({ expand, setExpand }) {
  4. return (
  5. <a
  6. onClick={() => setExpand(!expand)}
  7. rel="noopener noreferrer nofollow"
  8. >
  9. {expand ? <UpOutlined /> : <DownOutlined />}
  10. {expand ? ' 收起' : ' 展开'}
  11. </a>
  12. );
  13. }