Field 表单辅助工具

开发指南

何时使用

涉及到表单数据操作、校验的地方都可以用Field来管理数据。和组件关联后可以自动对表单数据进行回写、读取、校验。

使用注意

  • 使用Field init 过的组件, value onChange 必须放在 init 的第三个参数, 否则有可能被 init 覆盖。

  • Form已经和Field数据获取自动校验提示方面做了深度优化,建议在Form中使用Field, 请查看 Form demo。

  • initValue 类似组件的 defaultValue 只有在组件第一次render的时候才生效(ajax 异步调用设置 initValue 可能已经错过了第一次render)

  • autoUnmount 默认打开的,如果需要保留会 自动卸载的组件 数据请关闭此项

  • parseName=true 可以通过 getValues 获取到结构化的数据, 但是 getValue 还是必须传完整 key 值

基本使用

class Demo extends React.Component {
    field = new Field(this);    // 实例创建

    onClick = ()=>{
        console.log(this.field.getValue('name'));
    }
    render() {
        const init = this.field.init;

        // 注意:initValue只会在组件第一次初始化的时候被赋值,如果你是异步赋值请用setValue
        return <div>
            <Input {...init('name',{initValue:'first value'})} />
            <button onClick={this.onClick>获取数据</button>
        </div>
    }
}

更新数据

事件更新

class Demo extends React.Component {
    field = new Field(this);

    onClick = ()=>{
        this.field.setValue('name', 'newvalue');    // 赋值会自动触发render
    }
    render() {
        const init = this.field.init;

        return <div>
            <Input {...init('name')} />
            <button onClick={this.onClick}>设置数据</button>
        </div>
    }
}

props更新

class Demo extends React.Component {
    field = new Field(this);

    // 在组件挂载之前把数据设置进去(可以用initValue替代这种用法)
    componentWillMount() {
        this.field.setValue('name', 'init Name')
    }
    // 接收来自props的数据
    componentWillReceiveProps(nextProps) {
        this.field.setValue('name', nextProps.name)
    }
    render() {
        const init = this.field.init;

        return <div>
            <Input {...init('name')} />
        </div>
    }
}

ajax更新

class Demo extends React.Component {
    field = new Field(this);

    onClick = ()=>{
        Ajax({
            url:'/demo.json',
            success:(json)=>{
                // 回调事件中赋值更新
                this.field.setValue('name',json.name);
            }
        });
    }
    render() {
        const init = this.field.init;

        return <div>
            <Input {...init('name')} />
            <button onClick={this.onClick}>设置数据</button>
        </div>
    }
}

onChange更新监控

两种用法: 1. 统一管理

class Demo extends React.Component {
    field = new Field(this,{
        onChange:(name, value) => {
          switch(name) {
            case 'name1':
              this.field.setValue('name2','value set by name1');
              break;
            case 'name2':
              this.field.setValue('name1','value set by name2');
              break;
          }
        }
    });
    render() {
        const init = this.field.init;

        return <div>
          <Input {...init('name1')} />
          <Input {...init('name2')} />
        </div>
    }
}
  1. 各自管理

class Demo extends React.Component {
    render() {
        const init = this.field.init;

        return <div>
          <Input {...init('name1',{
              props:{
                onChange:(v)=>{
                  this.field.setValue('name2','value set by name1');
                }
              }
            })} />
          <Input {...init('name2',{
              props:{
                onChange:(v)=>{
                  this.field.setValue('name1','value set by name2');
                }
              }
            })} />
        </div>
    }
}

详细请查看demo演示 关联控制



基本

getValue setValue reset 的使用




0102030405060708090100



关联控制

组件之间的关联控制. onChange 统一管理。

自定义返回值

通过 getValueFromEvent 自定义从组件的 Event 获取 value 的方式







自定义错误

自己控制组件的 errors







agreement:



Array validate:


校验

校验的错误信息需要用getError获取

now length is:16

email: frankqian@qq.com

redux 中使用

在 redux 中使用, 在 componentWillReceiveProps 更新



自动卸载

autoUnmount 默认为 true,当组件被 unmount 的时候会自动删除数据. autoUnmount 设置为 false 后,会一直保存数据.

id
input
operation
1
2
3

动态表格

通过 spliceArray 可以删除数组格式 name (eg: name.{index}) 的数据, 并且自动订正其他 name 的 index - 1 问题


0102030405060708090100

组合使用

多组件混合使用




自定义受控字段

valueName 的默认值为 value,如果为其他需要用 valueName 指定



自定义组件

自己的组件如何接入 Field。

Object transfer

obj.b:   obj.c:

Array transfer

arr.0:   arr.1:

Object with Defaults

objWithDefaults.a:   objWithDefaults.b:

result:
{
  "objWithDefaults": {
    "a": 1,
    "b": 2
  },
  "obj": {
    "b": "test1",
    "c": "test2"
  },
  "arr": [
    "0",
    "1"
  ]
}


结构化解析

init('obj.b') 的数据转换成 obj={obj:{b:'value'}}





Hooks

在 functional component 里可使用 Field.useField 支持 hooks. 依赖: react@^16.8

API

初始化

let myfield = new Field(this [,options]);
参数说明类型可选值默认值
this传入调用class的thisReact.Component必须设置
options一些事件配置, 详细参数如下Object非必须

options 配置项

参数说明类型默认值
onChange所有组件的change都会到达这里setValue不会触发该函数Function(name,value)
parseName是否翻译init(name)中的name(getValues会把带.的字符串转换成对象)Booleanfalse
forceUpdate仅建议PureComponent的组件打开此强制刷新功能,会带来性能问题(500个组件为例:打开的时候render花费700ms, 关闭时候render花费400ms)Booleanfalse
scrollToFirstErrorfield.validate的时候滚动到第一个出错的组件, 如果是整数会进行偏移Boolean/Numbertrue
autoUnmount自动删除Unmout元素,如果想保留数据可以设置为falseBooleantrue
autoValidate是否修改数据的时候就自动触发校验, 设为 false 后只能通过 validate() 来触发校验Booleantrue
values初始化数据Object

API接口

new之后的对象提供的api接口 (例:myfield.getValues())(set 开头的api函数不要在render里面操作, 可能会触发死循环)

参数说明类型可选值默认值
init初始化每个组件,详细参数如下Function(name:String, option:Object)
getValues获取一组输入控件的值,如不传入参数,则获取全部组件的值Function([names: String[]])
getValue获取单个输入控件的值Function(name: String)
setValues设置一组输入控件的值(会触发render,请遵循react时机使用)Function(obj: Object)
setValue设置单个输入控件的值 (会触发render,请遵循react时机使用)Function(name: String, value)
validate校验并获取一组输入域的值与 ErrorFunction([names: String[]], options: Object, callback: Function(errors, values))
getError获取单个输入控件的 ErrorFunction(name: String)
getErrors获取一组输入控件的 ErrorFunction(name: String)
setError设置单个输入控件的 ErrorFunction(name: String, errors:String/ArrayString)
setErrors设置一组输入控件的 ErrorFunction(obj: Object)
reset重置一组输入控件的值、清空校验Function([names: String[]])
resetToDefault重置一组输入控件的值为默认值Function([names: String[]])
getState判断校验状态Function(name: String)'error' 'success' 'loading' ''''
getNames获取所有组件的keyFunction()
remove删除某一个或者一组控件的数据,删除后与之相关的validate/value都会被清空Function(name: String/String[])
spliceArray删除 name 是数组格式的数据, 并且自动处理其他 name 的数组错位问题Function(keyMatch: String, index: Number)

init

init(name, options, props)
参数说明类型可选值默认值
name必填输入控件唯一标志String
options.valueName组件值的属性名称,如 Checkbox 的是 checked,Input是 valueString'value'
options.initValue组件初始值(组件第一次render的时候才会读取,后面再修改此值无效),类似defaultValueany
options.trigger触发数据变化的事件名称String'onChange'
options.rules校验规则Array/Object
options.getValueFromEvent自定义从onChange事件中获取value的方式,一般不需要设置. 详细用法查看demo 自定义数据获取Function(value,...args) 参数顺序和组件是完全一致的
props组件自定义的事件可以写在这里Object
autoValidate是否修改数据的时候自动触发校验单个组件的校验, 设为 false 后只能通过 validate() 来触发校验Booleantrue

返回值

{id,value,onChange}

rules

{
    rules:[{ required: true }]
}

多个rule

{
    rules:[{required:true,trigger:'onBlur'},{pattern:/abcd/,message:'abcd不能缺'},{validator:(rule, value, callback)=>{callback('出错了')}}]
}
参数说明类型可选值使用类型
required不能为空Booleantrueundefined/null/“”/[] 会触发此规则)
pattern校验正则表达式正则
minLength字符串最小长度 / 数组最小个数NumberString/Number/Array
maxLength字符串最大长度 / 数组最大个数NumberString/Number/Array
length字符串精确长度 / 数组精确个数NumberString/Number/Array
min最小值NumberString/Number
max最大值NumberString/Number
format对常用 pattern 的总结Stringurl、email、tel、numberString
validator自定义校验,(校验成功的时候不要忘记执行 callback(),否则会校验不返回)Function(rule,value,callback)
trigger触发校验的事件名称String/ArrayonChange/onBlur/...onChange
message出错时候信息String

自定义组件接入Field标准

  • 支持受控模式(value+onChange) 必须

    • value 控制组件数据展现

    • onChange 组件发生变化时候的回调函数(第一个参数可以给到value)

  • 一次完整操作抛一次onChange事件 建议 比如有Process表示进展中的状态,建议增加API onProcess;如果有Start表示启动状态,建议增加API onStart

  • value={undefined}的时候清空数据, field 的 reset 函数会给所有组件下发 undefined 数据 建议

componentWillReceiveProps(nextProps) {
    if ('value' in nextProps ) {
        this.setState({
           value: nextProps.value === undefined? []: nextProps.value   //  设置组件的被清空后的数值
        })
    }
}

已知问题

  • 为何手动调用this.field.validate的时候进不了回调函数? 答: 是不是自定义了validator方法,确保callback在任何分支下都能被执行到。