基於antd Form組件打造超好用的表單組件—UForm

前言

博主最近在用antd Form組件開發表單功能,深深感慨antd Form組件功能也忒強大了,可是寫起來真的挺麻煩的,相信不少小夥伴在用antd Form組件的時候都有一樣的感覺吧。css

看一下antd官網的一個例子,須要Form.create包裝表單組件,而後表單每一項使用getFieldDecorator進行具體描述。node

import { Form, Input, Button, Checkbox } from 'antd';

const formItemLayout = {
  labelCol: { span: 4 },
  wrapperCol: { span: 8 },
};
const formTailLayout = {
  labelCol: { span: 4 },
  wrapperCol: { span: 8, offset: 4 },
};
class DynamicRule extends React.Component {
  state = {
    checkNick: false,
  };

  check = () => {
    this.props.form.validateFields(err => {
      if (!err) {
        console.info('success');
      }
    });
  };

  handleChange = e => {
    this.setState(
      {
        checkNick: e.target.checked,
      },
      () => {
        this.props.form.validateFields(['nickname'], { force: true });
      },
    );
  };

  render() {
    const { getFieldDecorator } = this.props.form;
    return (
      <div>
        <Form.Item {...formItemLayout} label="Name">
          {getFieldDecorator('username', {
            rules: [
              {
                required: true,
                message: 'Please input your name',
              },
            ],
          })(<Input placeholder="Please input your name" />)}
        </Form.Item>
        <Form.Item {...formItemLayout} label="Nickname">
          {getFieldDecorator('nickname', {
            rules: [
              {
                required: this.state.checkNick,
                message: 'Please input your nickname',
              },
            ],
          })(<Input placeholder="Please input your nickname" />)}
        </Form.Item>
        <Form.Item {...formTailLayout}>
          <Checkbox checked={this.state.checkNick} onChange={this.handleChange}>
            Nickname is required
          </Checkbox>
        </Form.Item>
        <Form.Item {...formTailLayout}>
          <Button type="primary" onClick={this.check}>
            Check
          </Button>
        </Form.Item>
      </div>
    );
  }
}

const WrappedDynamicRule = Form.create({ name: 'dynamic_rule' })(DynamicRule);
ReactDOM.render(<WrappedDynamicRule />, mountNode);
複製代碼

思考:能不能只傳data和fields字段,底層不須要關心表單項的生成過程呢。react

基本介紹

因而,博主費盡千辛萬苦封裝了一個超好用的UForm組件,只須要傳入data、fields props和onChange、onCancel、onSubmit回調便可渲染一個完整的表單了,支持表單渲染表單驗證修改回調提交回調取消回調git

<UForm
    data={data}
    fields={fields}
    onChange={onChange}
    onCancel={onCancel}
    onSubmit={onSubmit}
    />
複製代碼

目前UForm組件支持常規表單彈窗表單兩種,支持Form組件包含InputInputNumberTextareaSelectRadioCheckboxPasswordSwitchRatecustom(自定義ReactNode)github

documentation:dadaiwei.github.io/uform
npm:www.npmjs.com/package/ufo…npm

使用指南

1.安裝 UForm 依賴包bash

npm install uform --save-dev
複製代碼

2.引入依賴包antd

import UForm from "uform";
import "uform/dist/uform.css";
複製代碼

3.使用 UForm 組件app

<UForm
    data={data}
    fields={fields}
    onChange={onChange}
    onCancel={onCancel}
    onSubmit={onSubmit}
    />
複製代碼

代碼演示

通用表單

通用表單

代碼佈局

import React, { useState } from "react";
import UForm from "uform";
import "uform/dist/uform.css";

function NormalForm() {
  const [data, setData] = useState({
    name: "",
    size: 1,
    city: 0,
    area: "郊區",
    password: "",
    choosen: true,
    confirm: true,
    rate: 3,
    describe: ""
  });
  const fields = [
    {
      name: "name",
      label: "名稱",
      type: "input",
      placeholder: "請輸入名稱",
      rules: [
        {
          required: true,
          message: "請輸入名稱"
        }
      ]
    },
    {
      name: "size",
      label: "大小",
      type: "inputNumber",
      placeholder: "請輸入大小",
      rules: [
        {
          required: true,
          message: "請輸入名稱"
        }
      ]
    },
    {
      name: "city",
      label: "城市",
      type: "select",
      fieldData: [
        {
          name: "北京",
          value: 0
        },
        {
          name: "上海",
          value: 1
        },
        {
          name: "杭州",
          value: 2
        },
        {
          name: "深圳",
          value: 3
        }
      ],
      rules: [
        {
          required: true,
          message: "請輸入名稱"
        }
      ]
    },
    {
      name: "area",
      label: "地區",
      type: "radio",
      fieldData: ["城區", "郊區"]
    },
    {
      name: "confirm",
      label: "確認選擇",
      type: "checkbox",
      rules: [
        {
          required: true,
          message: "請確認選擇"
        }
      ]
    },
    {
      name: "custom",
      label: "自定義項",
      type: "custom",
      node: (
        <div>
          <h2>自定義表單項</h2>
        </div>
      )
    },
    {
      name: "password",
      label: "密碼",
      type: "password",
      rules: [
        {
          required: true,
          message: "請輸入密碼"
        }
      ]
    },
    {
      name: "choosen",
      label: "是否選擇",
      type: "switch",
      checkedChildren: "開",
      unCheckedChildren: "關",
      rules: [
        {
          required: true,
          message: "請輸入密碼"
        }
      ]
    },
    {
      name: "rate",
      label: "評分",
      type: "rate"
    },
    {
      name: "describe",
      label: "描述",
      type: "textarea",
      placeholder: "請輸入描述"
    }
  ];
  const onChange = (result) => {
    setData({
      ...data,
      ...result
    });
  };
  const onSubmit = (values) => {
    console.log(values);
  };
  const onCancel = () => {
    console.log("cancel");
  };
  return (
    <div>
      <div style={{ width: 600, marginLeft: 100 }}>
        <UForm
          data={data}
          fields={fields}
          onChange={onChange}
          onCancel={onCancel}
          onSubmit={onSubmit}
        />
      </div>
    </div>
  );
}
複製代碼

彈框表單

談框表單

代碼

import React, { useState } from "react";
import { Button } from "antd";
import UForm from "uform";
import "uform/dist/uform.css";

function ModalForm() {
  const { visible, setVisible } = useState(false);
  const [data, setData] = useState({
    name: "",
    size: 1,
    city: 0,
    area: "郊區",
    password: "",
    choosen: true,
    confirm: true,
    rate: 3,
    describe: ""
  });
  const fields = [
    {
      name: "name",
      label: "名稱",
      type: "input",
      placeholder: "請輸入名稱",
      rules: [
        {
          required: true,
          message: "請輸入名稱"
        }
      ]
    },
    {
      name: "size",
      label: "大小",
      type: "inputNumber",
      placeholder: "請輸入大小",
      rules: [
        {
          required: true,
          message: "請輸入名稱"
        }
      ]
    },
    {
      name: "city",
      label: "城市",
      type: "select",
      fieldData: [
        {
          name: "北京",
          value: 0
        },
        {
          name: "上海",
          value: 1
        },
        {
          name: "杭州",
          value: 2
        },
        {
          name: "深圳",
          value: 3
        }
      ],
      rules: [
        {
          required: true,
          message: "請輸入名稱"
        }
      ]
    },
    {
      name: "area",
      label: "地區",
      type: "radio",
      fieldData: ["城區", "郊區"]
    },
    {
      name: "confirm",
      label: "確認選擇",
      type: "checkbox",
      rules: [
        {
          required: true,
          message: "請確認選擇"
        }
      ]
    },
    {
      name: "custom",
      label: "自定義項",
      type: "custom",
      node: (
        <div>
          <h2>自定義表單項</h2>
        </div>
      )
    },
    {
      name: "password",
      label: "密碼",
      type: "password",
      rules: [
        {
          required: true,
          message: "請輸入密碼"
        }
      ]
    },
    {
      name: "choosen",
      label: "是否選擇",
      type: "switch",
      checkedChildren: "開",
      unCheckedChildren: "關",
      rules: [
        {
          required: true,
          message: "請輸入密碼"
        }
      ]
    },
    {
      name: "rate",
      label: "評分",
      type: "rate"
    },
    {
      name: "describe",
      label: "描述",
      type: "textarea",
      placeholder: "請輸入描述"
    }
  ];
  const onChange = (result) => {
    setData({
      ...data,
      ...result
    });
  };
  const onSubmit = (values) => {
    console.log(values);
  };
  const onCancel = () => {
    setVisible(false);
  };
  return (
    <div>
      <Button
        type='primary'
        onClick={() => {
          setVisible(true);
        }}>
        打開彈窗表單
      </Button>
      <div style={{ width: 600, marginLeft: 100 }}>
        <UForm
          type="modal"
          visible={visible}
          title='新建表單'
          data={data}
          fields={fields}
          onChange={onChange}
          onCancel={onCancel}
          onSubmit={onSubmit}
        />
      </div>
    </div>
  );
}
複製代碼

API

公共 API

屬性 說明 必填屬性 類型 可選值 默認值
type 使用通用表單或者彈框表單 false string norma | modal normal
layout 表單佈局 false string horizontal | vertical | inline horizontal
labelCol 表單 label 佔寬 false number 1-24 之間整數 4
wrapperCol 表單內容項佔寬 false number 1-24 之間整數,一般爲 24-labelCol 16
loading 肯定按鈕 loading false boolean true | false false
data 表單數據 true any[ ] - [ ]
fields 表單每一項特徵描述 true any[ ] - [ ]
onSubmit 表單提交回調 true Function(values) -
onChange 表單每一項修改回調 false Function(value) -
onCancel 表單取消回調 false Function( ) -

fields props

屬性 說明 必填屬性 類型 可選值 默認值
name 表單數據 name,與 data 中 key 值一致 true string -
type 表單項類型 true string input | inputNumber | textarea | select | radio | checkbox | password | switch | rate | custom(自定義項)
label 表單項 label true string -
rules 表單項限制規則,與 antd Form 限制規則一致 false object [ ] -
fieldData 適用於 type 爲 select/radio 的選擇項 true object [ ] -
placehoder 適用於 type 爲 input/textarea/select 的提示信息 false string -
node 適用於 type 爲 custom 的自定義 ReactNode true ReactNode -

特別說明:type 類型爲 select/radio時, fieldsData 是必填屬性, type 類型爲 custome 時, node 是必填屬性。

通用表單特有API

屬性 說明 必填屬性 類型 可選值 默認值
showCancelButton 是否展現取消按鈕 false boolean true | false true

彈框表單特有API

屬性 說明 必填屬性 類型 可選值 默認值
visible 彈框是否可見 true boolean true | false true
title 彈框標題 true string | ReactNode -
width 彈框寬度 false number - 600

總結

以上就是博主基於antd Form組件封裝的UForm組件,目前支持功能還比較簡單,後續會逐漸完善擴展該組件的功能,感興趣的小夥伴能夠試用下,真的簡單又好用。

以爲文章不錯的小夥伴能夠點個贊,灰常感謝^_^。

相關文章
相關標籤/搜索