Skip to content

Commit

Permalink
EasyField support ‘psssUtil’
Browse files Browse the repository at this point in the history
  • Loading branch information
Jiaqi Liu committed Aug 28, 2018
1 parent 5c02ef0 commit 88b4daa
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 61 deletions.
119 changes: 66 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Happy to build the forms in React ^\_^
* [`select`](#select)
* [`checkbox/radio`](#checkboxradio)
* [`checkbox/radio group`](#checkboxradio-group)
+ [`children | render | compnent`](#children--render--compnent)
+ [`children | render | component`](#children--render--component)
* [`native form widgets`](#native-form-widgets)
* [`custom component`](#custom-component)
+ [`name`](#name-1)
Expand All @@ -60,6 +60,7 @@ Happy to build the forms in React ^\_^
+ [`validMessage`](#validmessage)
+ [`checked / unchecked`](#checked--unchecked)
+ [`valuePropName` `changePropName` `focusPropName` `blurPropName`](#valuepropname-changepropname-focuspropname-blurpropname)
+ [`passUtil`](#passutil)
- [`<Form />`](#form-)
+ [`render` | `component`](#render--component)
+ [`$defaultValues`](#defaultvalues)
Expand Down Expand Up @@ -122,12 +123,12 @@ yarn add react-formutil

`react-formutil` 主要提供了一个 Field 组件和一个 Form 组件,另外还有几个基于此的高阶组件:

* `Field` 组件主要用来负责和具体的表单控件做状态的同步,并向顶层的 `Form` 注册自身。虽然它是一个标准的 react 组件,但是可以把它理解成单个表单控件的 Provider。
* `Form` 组件通过 `context` 提供了一些方法给 `Field` 组件,并且它增强了传递过来的子组件,向其传递了整个表单的状态。Form 可以理解为整个表单页面的 Provider。
* `withField` 是基于 `Field` 包装成高阶组件,方便习惯高阶方式的调用
* `withForm` 是基于 `Form` 包装成高阶组件,方便习惯高阶方式的调用
* `EasyField` 是基于 `Field` 进行的组件封装,方便直接调用浏览器原生控件去生成表单(可以参考 demo 中的例子)
* `connect` 是个高阶组件,用来给被包装的组件传递`$formutil` 对象,以供调用,返回的新组件必须位于某个 Form 组件的孙子辈才可以拿到`$formutil`
- `Field` 组件主要用来负责和具体的表单控件做状态的同步,并向顶层的 `Form` 注册自身。虽然它是一个标准的 react 组件,但是可以把它理解成单个表单控件的 Provider。
- `Form` 组件通过 `context` 提供了一些方法给 `Field` 组件,并且它增强了传递过来的子组件,向其传递了整个表单的状态。Form 可以理解为整个表单页面的 Provider。
- `withField` 是基于 `Field` 包装成高阶组件,方便习惯高阶方式的调用
- `withForm` 是基于 `Form` 包装成高阶组件,方便习惯高阶方式的调用
- `EasyField` 是基于 `Field` 进行的组件封装,方便直接调用浏览器原生控件去生成表单(可以参考 demo 中的例子)
- `connect` 是个高阶组件,用来给被包装的组件传递`$formutil` 对象,以供调用,返回的新组件必须位于某个 Form 组件的孙子辈才可以拿到`$formutil`

`react-formutil` 不像很多你能看到的其它的 react 表单库,它是非侵入性的。即它并不要求、也并不会强制渲染某种固定的 dom 结构。它只需要提供 `name` 值以及绑定好 `$render` 用来更新输入值,然后一切就会自动同步、更新。

Expand Down Expand Up @@ -196,10 +197,10 @@ yarn add react-formutil

该项必填,`name` 可以是一个简单的字符串,也可以是一个字符串表达式(该表达式执行没有 `scope`, 所以表达式中不能存在变量)

* `<Field name="username" />`
* `<Field name="list[0]" />`
* `<Field name="list[1].name" />`
* `<Field name="list[2]['test' + 124]" />`
- `<Field name="username" />`
- `<Field name="list[0]" />`
- `<Field name="list[1].name" />`
- `<Field name="list[2]['test' + 124]" />`

以上都是合法的 `name` 值。对于多层级的 `name` 值,生成的表单参数对象,也会基于该对象层级创建。例如,上面的示例,将会生成以下格式的表单参数对象:

Expand All @@ -214,8 +215,8 @@ yarn add react-formutil

该属性可以设置表单控件的默认值/初始值。如过不传递该参数,则默认值都为空字符串。通过该属性,你可以指定某个表单控件的默认值或初始值。

* `<Field $defaultValue="username" />`
* `<Field $defaultValue={{name: 'dog'}} />`
- `<Field $defaultValue="username" />`
- `<Field $defaultValue={{name: 'dog'}} />`

`$defaultValue` 可以是任意类型值。

Expand All @@ -242,9 +243,9 @@ yarn add react-formutil
校验被调用,会传入三个值:value、attr、props

* `value` 为当前 Field 的值
* `attr` 为校验标识值
* `props` 为当前传给 Field 的所有 props,还包括当前 Field 所属 Fom 的$formutil
- `value` 为当前 Field 的值
- `attr` 为校验标识值
- `props` 为当前传给 Field 的所有 props,还包括当前 Field 所属 Fom 的$formutil

```javascript
<Field
Expand Down Expand Up @@ -363,9 +364,9 @@ Field 会维护一个状态树,以及一些方法,并且会将状态和方
该对象会传递给子组件,子组件可以利用其中的方法来同步、修改表单状态:
* 用户输入时需要通过调用`$render`来更新新值到状态中
* 渲染表单项时,应该使用受控组件,根据 `$value` 来渲染
* 错误信息和校验状态可以通过 `$dirty` `$invalid` `$error`来渲染
- 用户输入时需要通过调用`$render`来更新新值到状态中
- 渲染表单项时,应该使用受控组件,根据 `$value` 来渲染
- 错误信息和校验状态可以通过 `$dirty` `$invalid` `$error`来渲染
> **需要强调的是,Field 默认不同步`$touched`/`$untouched``$focused` 状态,只有`$dirty`/`$pristine`会自动同步(首次调用`$render`会自动同步`$dirty`状态)**
> 如果你需要其它状态,需要自己去绑定相关事件来更新状态:
Expand All @@ -392,14 +393,14 @@ Field 的值实际是保存在状态里的该字段中,
Field 的一组状态:
* $dirty 控件被修改过
* $pristine 控件没有被修改过,与$dirty 互斥
* $touched 控件失去过焦点
* $untouched 控件没有失去过焦点
* $focused 焦点是否在当前控件
* $pending 是否正在进行异步检查
* $valid 表单所有控件均校验通过
* $invalid 表单中有至少一个控件校验不通过
- $dirty 控件被修改过
- $pristine 控件没有被修改过,与$dirty 互斥
- $touched 控件失去过焦点
- $untouched 控件没有失去过焦点
- $focused 焦点是否在当前控件
- $pending 是否正在进行异步检查
- $valid 表单所有控件均校验通过
- $invalid 表单中有至少一个控件校验不通过
#### `$error`
Expand Down Expand Up @@ -498,14 +499,14 @@ export default withField(FieldCustom, {
并且也也内置了一些常用的校验方法,例如:
* `required` 必填,如果是 group.checkbox,则必需至少选中一项 `required`
* `maxLength` 。最大输入长度,支持 group.checkbox。有效输入时才会校验 `maxLength="100"`
* `minLength` 最小输入长度,支持 group.checkbox。有效输入时才会校验 `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'}`
- `required` 必填,如果是 group.checkbox,则必需至少选中一项 `required`
- `maxLength` 。最大输入长度,支持 group.checkbox。有效输入时才会校验 `maxLength="100"`
- `minLength` 最小输入长度,支持 group.checkbox。有效输入时才会校验 `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` 时表示不进行该校验
Expand All @@ -515,16 +516,16 @@ export default withField(FieldCustom, {
当设置了 type 时,EasyField 将会尝试直接渲染浏览器表单元素。它支持以下类型:
* `input[type=text]`
* `input[type=number]`
* `input[type=search]`
* `input[type=password]`
* `input[type=checkbox]`
* `input[type=radio]`
* `select`
* `textarea`
* `group.radio`
* `group.checkbox`
- `input[type=text]`
- `input[type=number]`
- `input[type=search]`
- `input[type=password]`
- `input[type=checkbox]`
- `input[type=radio]`
- `select`
- `textarea`
- `group.radio`
- `group.checkbox`
> EasyField 对亚洲语言(中文、韩文、日文)输入法在输入过程中的的字母合成做了处理
Expand Down Expand Up @@ -582,7 +583,7 @@ export default withField(FieldCustom, {
</EasyField>
```
#### `children | render | compnent`
#### `children | render | component`
当 type 属性没有指定时,会根据这三个属性来进行渲染,并且将 EasyField 定义的同步回调方法(`onChange` `onFocus` `onBlur`)和当前值(`value`)传递下去。
Expand Down Expand Up @@ -716,15 +717,27 @@ function MyComponent({ current, onUpdate }) {
</label>;
```
#### `passUtil`
但使用自定义组件时,如果需要访问当前 Field 的状态,可以通过设置该参数,传入一个字符串,EasyField 会将状态通过该参数值传递给自定义组件:
```javascript
<EasyField name="custom" passUtil="$fieldutil">
{({ $fieldutil, onChange, value }) => {
return <input className={$fieldutil.$invalid ? 'has-error' : ''} onChange={onChange} value={value} />;
}}
</EasyField>
```
### `<Form />`
`Form` 也是一个标准的 react 组件,它类似 Field,同样可以以函数、或者普通组件当作子组件调用。它可以增强子组件,收集子 dom 树中的 `Field` 组件状态,并通过$formutil 传递给被调用组件。
经过 `Form` 增强的组件,会在其 `props` 中接收到一个`$formutil`对象。例如
* 你可以通过`$formutil.$params` 拿到整个表单的输入值
* 你可以通过`$formutil.$invalid``$formutil.$valid` 来判断表单是否有误
* 你可以通过`$formutil.$errors` 来获取表单的错误输入信息
- 你可以通过`$formutil.$params` 拿到整个表单的输入值
- 你可以通过`$formutil.$invalid``$formutil.$valid` 来判断表单是否有误
- 你可以通过`$formutil.$errors` 来获取表单的错误输入信息
`Form` 可以接收以下可选属性参数:
Expand Down Expand Up @@ -1204,9 +1217,9 @@ import { findDOMNode } from 'react-dom';
比如同时要收集用户的个人信息和工作信息,我们可以将其拆分为三个模块:
* `Userinfo.js` 用户基本信心的字段
* `Workinfo.js` 用户工作信息的字段
* `Submit.js` 提交区域(因为只有在 Form 组件下级才能拿到$formutil 信息)
- `Userinfo.js` 用户基本信心的字段
- `Workinfo.js` 用户工作信息的字段
- `Submit.js` 提交区域(因为只有在 Form 组件下级才能拿到$formutil 信息)
注: Submit.js 和 Workinfo.js 合并到一起也是可以的。
Expand Down Expand Up @@ -1386,7 +1399,7 @@ class MyForm extends Component {
是的,可以直接使用`EasyField`嵌套 `antd` 的组件即可。唯一需要注意的是,由于`react-formutil`默认所有的人表单域的值为空字符串,所以和`antd`一起使用时,部分组件由于不接收字符串值,所以需要设置`$defaultValue={undefined}`
另外我们也提供了一个独立的组件专门用于antd项目,它使用了`<Form.Item />`来对表单校验状态等做了同步,并且调用起来更加简洁:[`react-antd-formutil`](https://github.com/qiqiboy/react-antd-formutil)
另外我们也提供了一个独立的组件专门用于 antd 项目,它使用了`<Form.Item />`来对表单校验状态等做了同步,并且调用起来更加简洁:[`react-antd-formutil`](https://github.com/qiqiboy/react-antd-formutil)
[![npm](https://img.shields.io/npm/v/react-antd-formutil.svg?style=flat)](https://npm.im/react-antd-formutil)
Expand Down
19 changes: 12 additions & 7 deletions lib/EasyField/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ var EasyField = (_temp = _class = function (_Component) {
$validators = fieldProps.$validators,
$asyncValidators = fieldProps.$asyncValidators,
validMessage = fieldProps.validMessage,
passUtil = fieldProps.passUtil,
__TYPE__ = fieldProps.__TYPE__,
otherProps = _objectWithoutProperties(fieldProps, ['$defaultValue', '$defaultState', '$onFieldChange', '$validators', '$asyncValidators', 'validMessage', '__TYPE__']);
otherProps = _objectWithoutProperties(fieldProps, ['$defaultValue', '$defaultState', '$onFieldChange', '$validators', '$asyncValidators', 'validMessage', 'passUtil', '__TYPE__']);

var children = fieldProps.children;

Expand Down Expand Up @@ -210,22 +211,24 @@ var EasyField = (_temp = _class = function (_Component) {
onBlur && onBlur(ev);
}), _Object$assign));

var childPropsUtil = Object.assign({}, childProps, { $fieldutil: $util });
if (passUtil) {
childProps[passUtil] = $util;
}

if (TheComponent) {
return React.createElement(TheComponent, childPropsUtil);
return React.createElement(TheComponent, childProps);
}

if (isFunction(render)) {
return render(childPropsUtil);
return render(childProps);
}

if (isFunction(children)) {
return children(childPropsUtil);
return children(childProps);
}

return Children.map(children, function (child) {
return cloneElement(child, child && isFunction(child.type) ? childPropsUtil : childProps);
return cloneElement(child, childProps);
});
}
);
Expand Down Expand Up @@ -261,7 +264,9 @@ var EasyField = (_temp = _class = function (_Component) {
blurPropName: PropTypes.string,

$parser: PropTypes.func,
$formatter: PropTypes.func
$formatter: PropTypes.func,

passUtil: PropTypes.string
}, _class.defaultProps = {
validMessage: {},
valuePropName: 'value',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-formutil",
"version": "0.3.1",
"version": "0.3.2",
"description": "Happy to build the forms in React ^_^",
"main": "lib/index.js",
"directories": {
Expand Down

0 comments on commit 88b4daa

Please sign in to comment.