Skip to content
Happy to use react-formutil in the project based on ant-design ^_^
JavaScript TypeScript
Branch: master
Clone or download

Latest commit

Fetching latest commit…
Cannot retrieve the latest commit at this time.

Files

Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
dist
docs
jest
npm
src
.gitignore
.npmignore
LICENSE
README.md
babel.config.json
index.d.ts
package.json
rollup.config.js
tsconfig.json

README.md

react-antd-formutil

npm peerDependencies definitionTypes gzip download issues license github github github github

react-antd-formutil

Happy to use react-formutil in the project based on ant-design@3&4 ^_^

ant-design 项目,结合 react-formutil 来快速构建表单。支持所有的ant-design输入型(data-entry)组件。

如果你在使用其他 react 组件库,可以查阅:

  1. react-bootstrap react-bootstrap-formutil npm
  2. react-md react-md-formutil npm
  3. Material-UI react-material-formutil npm

安装 Installation

react-antd-formutil

react-antd-formutil1.0.0版本开始,同时支持 Ant Design 3.x4.x版本

# npm
npm install react-antd-formutil --save

# yarn
yarn install react-antd-formutil

使用 Usage

react-antd-formutil 整合了 react-formutil 的组件,所以可以直接从react-antd-formutil中导出所需要的 react-formutil 组件。不用单独从 react-formutil 中导出。

先看一个使用示例(点击查看在线完整示例: react-antd-formutil on codesandbox.io):

import React, { Component } from 'react';
import { withForm, FormItem } from 'react-antd-formutil';
import { Input, Form } from 'antd'; // 导入antd的Input组件

@withForm
class MyForm extends Component {
    submit = () => {
        const { $invalid, $getFirstError, $params } = this.props.$formutil;

        if ($invalid) {
            alert($getFistError());
        } else {
            // submit your data
        }
    };

    render() {
        return (
            <Form onSubmit={this.onSubmit}>
                <FormItem
                    name="username"
                    itemProps={{
                        label: 'Username'
                    }}>
                    <Input />
                </FormItem>
            </Form>
        );
    }
}

FormItemreact-antd-formuitl 新增加的组件,withFormreact-formutil的组件(没错,你可以直接从react-antd-formutil中导出react-formutil的组件啦)。

只需要将ant-design的交互组件,嵌套在FormItem下,即可实现自动的表单状态同步。

<FormItem />

要实现将ant-design的交互组件的值能同步到 react-formutil 的状态中,需要通过 FormItem 这个组件来实现中间态绑定。

它的作用有些类似 antd 中的getFieldDecorator方法,但是用法比getFieldDecorator更优雅,更 JSX 语法。FormItem完全是标签声明式用法,它是对 antd 的Form.Item组件的再次封装。

所以FormItem会完整实现Form.Item所可以显示的校验状态、错误暂时等 UI 变化。

如果给 FormItem 传递了多个子节点,可能会出现无法非预期的异常情况。你可以了解如何正确的使用FormItem嵌套渲染多个节点元素?

支持传递的属性

FormItem可以接收所有antd中的Form.Item组件所接收的所有属性,另外还新增以下属性支持:

name

设置输入项的 name 值,表单项将会以 name 作为 key 收集到 formutil 的状态中。支持嵌套语法 (同react-formutilField同名参数,可以参考 name

$defaultValue

设置该表单项的默认值 (同react-formutilField同名参数,可以参考$defaultvalue

$validators

设置校验方法 (同react-formutilField同名参数, 可以参考 $validators

同 react-formutil 的 EasyField,FormItem 也内置了同样的校验规则:

  • required 必填 required
  • maxLength 。最大输入长度,有效输入时才会校验 maxLength="100"
  • minLength 最小输入长度,有效输入时才会校验 minLength="10"
  • max 最大输入数值,仅支持 Number 比较。有效输入时才会校验 max="100"
  • min 最小输入数值,仅支持 Number 比较。有效输入时才会校验 min="10"
  • pattern 正则匹配。有效输入时才会校验 pattern={/^\d+$/}
  • enum 枚举值检测。有效输入时才会校验 enum={[1,2,3]}
  • checker 自定义校验函数。checker={value => value > 10 && value < 100 || '输入比如大于10小与100'}

注:校验属性的值为 null 时表示不进行该校验

内置的校验规则无需再次声明,除非规则不符合预期,需要替换,则可以通过$validators 传递同名校验方法即可替换默认的。另外,内置的校验规则,如果校验不通过,会尝试去 validMessage 匹配错误信息。

itemProps

该属性为要传递给Form.Item组件的配置项:

<FormItem
    itemProps={{
        label: 'Username',
        colon: false
    }}>
    <Input />
</FormItem>
$parser

请参考react-formutil$parser介绍。

$formatter

请参考react-formutil$formatter介绍。

checked unchecked

对于 <Switch /> <Checkbox /> <Radio /> 这三种组件,其值默认是 checked 属性,为布尔值。可以通过checked unchecked来设置 checked 状态时所要映射的值:

<FormItem checked="yes" unchecked="no">
    <Switch />
</FormItem>

该示例中, 当 Switch 为开时,获取的值将为 yes。

$validateLazy

可以用来优化表单的校验速度,请参考: $validateLazy

$memo

可以用来优化当前表单项的性能,避免过多的重复渲染。如果你遇到了表单性能问题,可以尝试该属性来改善。

详细解释和使用、注意事项请参考: $memo

validMessage

设置校验结果的错误信息。

<FormItem
    name="username"
    required
    validMessage={{
        required: '请输入用户名'
    }}>
    <Input />
</FormItem>
valuePropName changePropName focusPropName blurPropName

该四个参数可以用来设置绑定到组件上的值或者值变动、是否聚焦等事件回调。该项一般不需要设置,FormItem 已经针对 antd 中的所有 data-entry 型组件做了兼容处理。

对于一些特殊场景,例如不需要同步 focusblur,则可以通过将该值设为{null}来禁用:

//禁用focus、blur状态同步
<FormItem focusPropName={null} blurPropName={null} name="username">
    <Input />
</FormItem>
getValueFromEvent

请参考 getValueFromEvent()

noStyle

该属性从 v1.1.0 起可用

该属性同时兼容antd@3.xantd@4.x,都可以使用!

noStyleAntDesign v4.0中新版本的Form.ItemnoStyle类似,可以用来控制是否输出Form.Item的额外的样式元素。缺省情况下默认值为false

noStyletrue时,将会只渲染字段节点本身,但是其表单状态依然会被处理收集。此时,如果其存在父级嵌套的FormItem,那么其表达校验状态将会传递给父级的FormItem来展现。

这对于连续的紧凑型表单元素将非常有用!可以避免校验错误描述信息都堆叠在一起! 但是没有额外的样式显示,包括表单校验状态都无法显示了。此时可以在其外层包裹一层不带nameFormItem,这些noStyle的表单项就会把他们自身的状态向上进行注册显示了!

但是有以下几点需要注意:

  1. 最外层的FormItem不能设置name属性,否则将不会被当作子级的校验状态容器
  2. 内层的FormItem需要添加相应的name值(向表单控制器注册自身)以及noStyle属性(不渲染额外的样式,避免和上层冲突)
// 这里不能设置name
<FormItem label="FormItem Group">
    <Input.Group compact>
        {/* 与普通的FormItem用法一致,只是多了个noStyle */}
        <FormItem name="address.province" noStyle required validMessage={{ required: 'Province requird!' }}>
            <Select placeholder="Select province">
                <Select.Option value="Zhejiang">Zhejiang</Select.Option>
                <Select.Option value="Jiangsu">Jiangsu</Select.Option>
            </Select>
        </FormItem>

        <FormItem name="address.street" noStyle required validMessage={{ required: 'Street requird!' }}>
            <Input style={{ width: '50%' }} placeholder="Input street" />
        </FormItem>
    </Input.Group>
</FormItem>

以上运行示例请参考 示例

errorLevel

用来覆盖全局的 errorLevel 设置。参考setErrorLevel(level)

setErrorLevel(level)

setErrorLevel 该方法可以用来全局设置错误信息何时出现,有三个级别可以设置:

  • 0$dirty $touched $invalid 都为 true 时
  • 1$dirty $invalid 都为 true 时
  • 2$invalid 为 true 时
  • off 关闭错误显示

默认值为 1

注意,该方法影响全局,如果只是希望单独对某个表单项进行设置,可以通过errorLevel属性进行设置:参考errorLevel

import { setErrorLevel } from 'react-antd-formutil';

setErrorLevel(0);

// 当关闭错误显示时,errorLevel='off',你可以手动自行设置错误展示方式:
<FormGroup
    name="errorOff"
    errorLevel="off"
    itemProps={{
        validateStatus: $formutil.$errors.errorOff ? 'error' : undefined,
        help: $formutil.$errors.errorOff ? <div>出错啦</div> : null
    }}>
    <Input />
</FormGroup>;

支持的组件

AutoComplete
Checkbox

支持Checkbox.Group

Cascader
DatePicker

DatePicker TimePicker DatePicker.WeekPicker DatePicker.MonthPicker DatePicker.RangePicker 等几个日期类组件,都是深度结合了moment使用的。如果希望收集到表单中的值是格式化好的时间字符串,可以通过$parser $formatter实现:

<FormItem name="datepicker" $parser={moment => moment.format('YYYY-MM-DD')} $formatter={date => moment(date)}>
    <DatePicker />
</FormItem>

对于DatePicker.RangePicker,由于其值是一个数组,所以需要这样处理:

<FormItem
    name="datepicker"
    $parser={moments => moments.map(moment => moment.format('YYYY-MM-DD'))}
    $formatter={dates => dates.map(date => moment(date))}>
    <DatePicker.RangePicker />
</FormItem>
InputNumber
Input
Mentions
Pagination

Pagination 并非antd所归纳的data entry组件,但是其接口设计也可以支持FormItem

<FormItem name="page" $defaultValue={2}>
    <Pagination pageSize={10} total={100} />
</FormItem>
Rate
Radio

支持Radio.Group

Switch

Switch Checkbox(不包括Checkbox.Group) Radio(不包括Radio.Group)三个组件,可以通过给FormItem传递checked unchecked属性来改变被勾选时所映射到表单状态中的值:

<FormItem checked="yes" unchecked="no">
    <Switch />
</FormItem>
Slider
Select
TreeSelect
Transfer

Transfer收集到表单状态中的是targetKeys

TimePicker

参考 DatePicker

Upload

Upload组件非常特殊,其接受fileList对象作为整个组件的状态。而实际业务中,往往只需要获取上传文件的返回的地址,或者一组文件的地址。可以通过$parser控制如何获取上传结果的值,并且可以通过$parser的第二个回调方法$setViewValue来控制fileList对象,实现对文件上传数量的控制。

单个文件上传,获取单个文件上传地址

<FormItem
    name="upload"
    $formatter={url =>
        url && [
            {
                url,
                uid: url,
                status: 'done',
                name: url.split('/').slice(-1)[0]
            }
        ]
    }
    $parser={(info, $setViewValue) => {
        // 必不可少,限制只能上传一个文件
        $setViewValue(info.fileList.slice(-1));

        if (info.file.status === 'done') {
            return info.file.response.url;
        }
    }}
    itemProps={{ ...formItemLayout, label: 'Upload' }}
    required>
    <Upload {...uplodConfig}>
        <Button>
            <UploadOutlined /> Click to Upload
        </Button>
    </Upload>
</FormItem>

多文件列表上传,获取多个文件上传地址数组

<FormItem
    name="upload"
    $formatter={urls =>
        urls &&
        urls.map(url => ({
            url,
            uid: url,
            status: 'done',
            name: url.split('/').slice(-1)[0]
        }))
    }
    $parser={(info, $setViewValue) => {
        // 限制最大上传文件数量为3,如果不需要限制,可以移除该行,或者修改该值
        $setViewValue(info.fileList.slice(-3));

        return info.fileList.filter(file => file.status === 'done').map(file => file.url || file.response.url);
    }}
    itemProps={{ ...formItemLayout, label: 'Upload' }}
    required>
    <Upload {...uplodConfig}>
        <Button>
            <UploadOutlined /> Click to Upload
        </Button>
    </Upload>
</FormItem>

动态className

FormGroup会自动给表单节点增加与该表单项校验状态相关的 className:

  • has-error
  • is-invalid
  • is-valid
  • is-touched
  • is-untouched
  • is-focused
  • is-unfocused
  • is-dirty
  • is-pristine

FAQ

给组件设置的onChange、onFocus等方法无效、不执行

FormItem会覆盖掉直接添加到 antd 组件上的onFocus onBlur onChange方法,所以如果需要这三个事件方法,需要添加到 FormItem上:

<FormItem name="test" onChange={ev => console.log('change', ev)} onFocus={ev => console.log('focus', ev)}>
    <Input />
</FormItem>

RangePicker 在safari下假死?

经过 debug,在3.8.x版本上,依然存在对RangePicker设置onFocus onBlur会异常频繁触发(比如在光标经过日期选择面板中每个数字时)的问题。可以禁用onFocus onBlur状态同步:

<FormItem name="datepicker" focusPropName={null} blurPropName={null}>
    <DatePicker.RangePicker />
</FormItem>

在生产环境(NODE_ENV==='production')部分组件调用有异常?

如果在生产环境,发现例如Checkbox Radio Switch等组件无法正确捕获用户输入的值,这种情况一般是由于项目中使用了babel-plugin-import插件。

react-antd-formutil中是使用 import { Switch } from 'antd' 这种写法来调用 Switch 组件的,而babel-plugin-import插件会将项目源代码中的类似语句,替换成import Switch from 'antd/lib/switch'。这两种写法获取到的Switch其实并不是严格意义上的相等,前者是对后者的又一层导出封装。

而由于babel-plugin-import一般仅仅会配置成仅仅对项目代码进行处理,所以处于项目node_modules目录中的react-antd-formutil中的语句不会被处理。我们需要通过修改项目 webpack 配置的方式,来使babel-plugin-import插件能处理react-antd-formutil的代码。

可以编辑项目的 webpack 配置(只需要配置生产环境的构建配置即可),在rules模块下添加以下的代码:

{
    test: /\.(js|mjs)$/,
    include: /react-antd-formutil/, // 仅仅处理react-antd-formutil即可
    loader: require.resolve('babel-loader'),
    options: {
        babelrc: false,
        plugins: [[
            "import",
            {
                "libraryName": "antd"
            },
            "antd"
        ]]
    }
}

如何正确的使用FormItem嵌套渲染多个节点元素?

你可以通过给给children属性传递render props函数,来自由定义要渲染出的节点。但是请注意,当传递一个render props函数时,需要手动绑定相关绑定事件和 value 属性!

children函数接受一个$fieldHandler的对象,默认情况下其包含value onChange onFocus onBlur四个属性,但是如果你给FormItem传递了valuePropName等属性的话,这个值将会变为你通过valuePropName所定义的名字。

更具体解释可以参考 react-formutil.$fieldHandler

<FormItem name="username">
    {$fieldHandler => (
        <>
            <Input {...$fieldHandler} />
            <div>其它节点内容</div>
        </>
    )}
</FormItem>
You can’t perform that action at this time.