1. 程式人生 > >編寫antd配置表單組件

編寫antd配置表單組件

items dex pure 返回 輸入 ret ... 自帶 ops

編寫antd配置表單組件

整體思路

  1. 抽取formitem的配置數組:包含組件類型、名稱、label名稱,相關的opts和擴展的opts,傳遞進入組件
  2. 組件通過Form.create()進行表單創建,能夠帶有form屬性。並且上層組件引用後能夠ref的方式獲取form進行操作處理
  3. 基於form能夠抽取出來,上層組件能夠對下層組件進行調用和操作,在此基礎上還能夠進行擴展配置和擴展功能的實現
  4. 組件通過props中獲取配置數組,動態生成FormItem的表單元素,實現動態配置表單的功能
  5. 組件通過在create中的mapPropsToFields中將外部對象數據data綁定到內部表單Item中了

實例實現代碼,基於react和antd,類似的組件實現思路一致

組件js

import React, { PureComponent } from 'react';
import { Row, Form, Input, Col } from 'antd';
import FormItem from 'antd/lib/form/FormItem';
import BaseDataForm from '.';

// 通用組件
class _BaseDataForm extends PureComponent {

  // 默認屬性
  defaultProps = {
    fields: [], // 外部傳遞進來的配置數據
  }

  state = {
  }

  getFromItems = () => {
    const { form } = this.props;
    const { getFieldDecorator } = form;
    const { fields, labelCol, wrapperCol } = this.props;
    const children = [];// 定義返回值數組
    const fieldsinput = fields || [];
    const labelColinput = labelCol || 7;
    const wrapperColinput = wrapperCol || 15;
    const formItemLayout = {
      labelCol: { span: labelColinput },
      wrapperCol: { span: wrapperColinput },
    };
    for (let index = 0; index < fieldsinput.length; index += 1) {
      const field = fieldsinput[index];
      let item = '';
      if (field.type === 'Input' || field.type === 'password') {
        // this.props.form.getFieldDecorator(id, options) 使用功能這個包裝空間,id等於屬性名
        item = getFieldDecorator(field.name, field.fieldDecoratorOps)(
          <Input {...field.elementOpts} />
        );
      }
      // 拼裝表格
      children.push(
        <Col key={index}>
          <FormItem {...formItemLayout} label={field.label}>
            {item}
          </FormItem>
        </Col>
      );
    }
    return children;
  }

  render() {
    return (
      <Form>
        <Row>{this.getFields()}</Row>
      </Form>
    );
  }
}

導入js

// 經過Form.create包裝過的組件會自帶this.props.form
const BaseDataForm = Form.create({
  mapPropsToFields: (props) => {
    // 把父組件的屬性映射到表單項上(如:把 Redux store 中的值讀出),需要對返回值中的表單域數據用 Form.createFormField 標記,註意表單項將變成受控組件, error 等也需要一並手動傳入
    const { fields = [], data = [] } = props;
    const values = {};
    fields.map(item => {
      const fieldName = item.name;
      let value = data[fieldName];
      if (fieldName.indexOf('.' !== -1)) {
        try {
          // eslint-disable-next-line no-eval
          value = eval('data.' + fieldName);
          // 特殊多層結構數據獲取值
        } catch (error) {
          // eslint-disable-next-line no-console
          console.error(error);
        }
      }
      if (value !== undefined && value !== null) {
        // 特殊數據處理
      }
      values[fieldName] = Form.createFormField({ value });
      return item;
    });
    return values;
  },
})(_BaseDataForm);
export default BaseDataForm;

實例js

class Test extends PureComponent {

  exampleFields = [
    {
      type: 'Input',
      name: 'test',
      label: '輸入1',
      fieldDecoratorOps: {}, // 表單綁定屬性
      elementOpts: {}, // 標簽屬性
    },
    {
      type: 'Input',
      name: 'test2',
      label: '輸入2',
      fieldDecoratorOps: {}, // 表單綁定屬性
      elementOpts: {}, // 標簽屬性
    },
  ];

  saveFormRef = (form) => {
    this.form = from;
  }

  getFormData = () => {
    return this.form.getFieldsValue();
  }

  render() {
    return (
      <BaseDataForm
        ref={this.saveFormRef} // 通過ref將對應的表單from組件映射出來,能夠直接調用
        data={{}} // data在創建表單的時候做了一次綁定,這個綁定能夠將當前值顯示進去
        fields={exampleFields}
      />
    );
  }
}

編寫antd配置表單組件