Field 表单数据获取、校验工具

如果项目中使用的是 1.x 版本的基础组件(@alifd/next),请在左侧导航顶部切换组件版本。

安装方法

  1. 在命令行中执行以下命令npm install @icedesign/base@latest -S

开发指南

何时使用

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

使用注意

  • 使用Field init 过的组件,请勿再定义 ref value onChange 事件, 有可能被 init 覆盖。

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

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

基本使用

  1. class Demo extends React.Component {
  2. field = new Field(this); // 实例创建
  3. onClick = ()=>{
  4. console.log(this.field.getValue('name'));
  5. }
  6. render() {
  7. const init = this.field.init;
  8. // 注意:initVaue只会在组件第一次初始化的时候被赋值,如果你是异步赋值请用setValue
  9. return <div>
  10. <Input {...init('name',{initValue:'first value'})} />
  11. <button onClick={this.onClick>获取数据</button>
  12. </div>
  13. }
  14. }

更新数据

事件更新

  1. class Demo extends React.Component {
  2. field = new Field(this);
  3. onClick = ()=>{
  4. this.field.setValue('name', 'newvalue'); // 赋值会自动触发render
  5. }
  6. render() {
  7. const init = this.field.init;
  8. return <div>
  9. <Input {...init('name')} />
  10. <button onClick={this.onClick}>设置数据</button>
  11. </div>
  12. }
  13. }

props更新

  1. class Demo extends React.Component {
  2. field = new Field(this);
  3. // 在组件挂载之前把数据设置进去(可以用initValue替代这种用法)
  4. componentWillMount() {
  5. this.field.setValue('name', 'init Name')
  6. }
  7. // 接收来自props的数据
  8. componentWillReceiveProps(nextProps) {
  9. this.field.setValue('name', nextProps.name)
  10. }
  11. render() {
  12. const init = this.field.init;
  13. return <div>
  14. <Input {...init('name')} />
  15. </div>
  16. }
  17. }

ajax更新

  1. class Demo extends React.Component {
  2. field = new Field(this);
  3. onClick = ()=>{
  4. Ajax({
  5. url:'/demo.json',
  6. success:(json)=>{
  7. // 回调事件中赋值更新
  8. this.field.setValue('name',json.name);
  9. }
  10. });
  11. }
  12. render() {
  13. const init = this.field.init;
  14. return <div>
  15. <Input {...init('name')} />
  16. <button onClick={this.onClick}>设置数据</button>
  17. </div>
  18. }
  19. }

onChange更新监控

两种用法:1. 统一管理

  1. class Demo extends React.Component {
  2. field = new Field(this,{
  3. onChange:(name, value) => {
  4. switch(name) {
  5. case 'name1':
  6. this.field.setValue('name2','value set by name1');
  7. break;
  8. case 'name2':
  9. this.field.setValue('name1','value set by name2');
  10. break;
  11. }
  12. }
  13. });
  14. render() {
  15. const init = this.field.init;
  16. return <div>
  17. <Input {...init('name1')} />
  18. <Input {...init('name2')} />
  19. </div>
  20. }
  21. }
  • 各自管理
  1. class Demo extends React.Component {
  2. render() {
  3. const init = this.field.init;
  4. return <div>
  5. <Input {...init('name1',{
  6. props:{
  7. onChange:(v)=>{
  8. this.field.setValue('name2','value set by name1');
  9. }
  10. }
  11. })} />
  12. <Input {...init('name2',{
  13. props:{
  14. onChange:(v)=>{
  15. this.field.setValue('name1','value set by name2');
  16. }
  17. }
  18. })} />
  19. </div>
  20. }
  21. }

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

方法

初始化

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

options 配置项

参数说明类型默认值
onChange所有组件的 change 都会到达这里setValue 不会触发该函数Function(name,value)
parseName是否翻译init(name)中的name(getValues 会把带.的字符串转换成对象)Booleanfalse
forceUpdate仅建议 PureComponent 的组件打开此强制刷新功能,会带来性能问题(500 个组件为例:打开的时候 render 花费 700ms, 关闭时候 render 花费 400ms)Booleanfalse
scrollToFirstErrorfield.validate 的时候滚动到第一个出错的组件Booleanfalse (1.0 版本会改成 true)
autoUnmount自动删除(remove) Unmout 元素, getValues 不会出现冗余数据Booleanfalse (1.0 版本会改成 true)
deepReset强制重置数据(设置所有数据为 undefined,业务组件需要自己支持 value=undefined 情况清空数据)(版本要求>next@0.15)Booleanfalse (1.0 版本会改成 true)

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重置一组输入控件的值、清空校验, 第二个参数控制是否回到 defaultValueFunction([names: String[]], backToDefault:Boolean)backToDefault=false
getState判断校验状态Function(name: String)'error' 'success' 'validating' ''''
getNames获取所有组件的 keyFunction()
remove删除某一个或者一组控件的数据,删除后与之相关的 validate/value 都会被清空Function(name: String/String[])

init

  1. init(name, options);
参数说明类型可选值默认值
name必填输入控件唯一标志String
options.valueName组件值的属性名称,如 Checkbox 的是 checked,Input 是 valueString'value'
options.initValue组件初始值(组件第一次 render 的时候才会读取,后面再修改此值无效),类似 defaultValueany
options.trigger触发数据变化的事件名称String'onChange'
options.rules校验规则Array/Object
options.props组件自定义的事件可以写在这里,其他会透传(小包版本^0.3.0 支持,大包^0.7.0 支持)Object
options.getValueFromEvent自定义从onChange事件中获取 value 的方式,一般不需要设置. 详细用法查看 demo 自定义数据获取Function(value,…args) 参数顺序和组件是完全一致的

返回值

  1. {
  2. id, value, onChange;
  3. }

rules

  1. {
  2. rules: [{ required: true }];
  3. }

多个 rule

  1. {
  2. rules: [
  3. { required: true, trigger: 'onBlur' },
  4. { pattern: /abcd/, message: 'abcd不能缺' },
  5. {
  6. validator: (rule, value, callback) => {
  7. callback('出错了');
  8. }
  9. }
  10. ];
  11. }
参数说明类型可选值默认值
required不能为空 (不能和pattern同时使用)Booleantrue
message出错时候信息String
type被校验数据类型(注意 type:'number' 表示数据类型为Number,而不是字符串形式的数字,字符串形式的数字请用pattern:/^[0-9]$/) 详细文档见StringString/Array/url/email/…String
pattern校验正则表达式正则表达式(例如:/^[0-9]$/表示字符串形式的 number)
len长度校验,如果 max、mix 混合配置,len 的优先级最高Number
min字符最小长度Number
max字符最大长度Number
whitespace是否进行空白字符校验(true 进行校验)Boolean
validator自定义校验,(校验成功的时候不要忘记执行 callback(),否则会校验不返回)Function(rule,value,callback)
trigger触发校验的事件名称String/ArrayonChange/onBlur/…onChange

更加详细的 rules 建议规则见async-validator的 rules 项

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

    • value 控制组件数据展现

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

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

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

  1. componentWillReceiveProps(nextProps) {
  2. if ('value' in nextProps ) {
  3. this.setState({
  4. value: nextProps.value === undefined? []: nextProps.value // 设置组件的被清空后的数值
  5. });
  6. }
  7. }

已知问题

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

代码示例

自动卸载

autoUnmount 会自动把Unmout的元素删除。getValues里面也会自动remove组件数据

Field 表单数据获取、校验工具 - 图1

查看源码在线预览

  1. import { Input, Select, Button, Field } from "@icedesign/base";
  2. class App extends React.Component {
  3. field = new Field(this, {
  4. autoUnmount: true
  5. });
  6. onGetValue() {
  7. console.log(this.field.getValues());
  8. }
  9. render() {
  10. const { init, getValue } = this.field;
  11. return (
  12. <div className="demo">
  13. <Select {...init("select", { initValue: "yes" })}>
  14. <li value="yes">yes</li>
  15. <li value="no">no</li>
  16. </Select>
  17. <br />
  18. {getValue("select") === "yes" ? <Input {...init("input")} /> : null}
  19. <br />
  20. <br />
  21. <Button type="primary" onClick={this.onGetValue.bind(this)}>
  22. getValue
  23. </Button>
  24. </div>
  25. );
  26. }
  27. }
  28. ReactDOM.render(<App />, mountNode);
  1. .demo .next-btn {
  2. margin-right: 5px;
  3. }

基本

getValue setValue reset 的使用

Field 表单数据获取、校验工具 - 图2

查看源码在线预览

  1. import { Input, Button, Field } from "@icedesign/base";
  2. class App extends React.Component {
  3. field = new Field(this);
  4. onGetValue() {
  5. console.log(this.field.getValue("input"));
  6. }
  7. render() {
  8. const { init, setValue, reset } = this.field;
  9. return (
  10. <div className="demo">
  11. <Input {...init("input", { initValue: "test" })} />
  12. <br />
  13. <br />
  14. <Button type="primary" onClick={this.onGetValue.bind(this)}>
  15. getValue
  16. </Button>
  17. <Button
  18. type="primary"
  19. onClick={() => setValue("input", "set me by click")}
  20. >
  21. setValue
  22. </Button>
  23. <Button onClick={() => reset()}>reset</Button>
  24. </div>
  25. );
  26. }
  27. }
  28. ReactDOM.render(<App />, mountNode);
  1. .demo .next-btn {
  2. margin-right: 5px;
  3. }

自定义组件使用Field

达到效果:Field可以getValue从onChange获取数据,可以setValue通过value控制组件数据切换完全支持: 组件支持受控, 也就是支持两个api:value onChange. value: 设置组件的数据; onChange: 在组件修改的时候在第一个数暴露数据最低标准: 组件有onChange事件可以读取组件数据。达到效果:Field可以getValue,但是setValue无效自己的组件如何接入Field。

Field 表单数据获取、校验工具 - 图3

查看源码在线预览

  1. import { Button, Field } from "@icedesign/base";
  2. // 最简单的组件
  3. class Custom extends React.Component {
  4. static propTypes = {
  5. onChange: React.PropTypes.func, // Field 从组件拿最新值
  6. value: React.PropTypes.array // Feild 给组件设置新值
  7. };
  8. constructor(props) {
  9. super(props);
  10. this.state = {
  11. value: typeof props.value === "undefined" ? [] : props.value
  12. };
  13. }
  14. // 用到了state的需要接受props传过来的value,以更新组件
  15. componentWillReceiveProps(nextProps) {
  16. if ("value" in nextProps) {
  17. this.setState({
  18. value: typeof nextProps.value === "undefined" ? [] : nextProps.value
  19. });
  20. }
  21. }
  22. onAdd = () => {
  23. let value = this.state.value.concat([]);
  24. value.push("new");
  25. this.setState({
  26. value
  27. });
  28. this.props.onChange(value);
  29. };
  30. render() {
  31. return (
  32. <div className="custom">
  33. {this.state.value.map((v, i) => {
  34. return <Button key={i}>{v}</Button>;
  35. })}
  36. <Button type="primary" onClick={this.onAdd.bind(this)}>
  37. Add +{" "}
  38. </Button>
  39. </div>
  40. );
  41. }
  42. }
  43. /* eslint-disable react/no-multi-comp */
  44. class App extends React.Component {
  45. field = new Field(this, {
  46. deepReset: true
  47. });
  48. onGetValue() {
  49. console.log(this.field.getValue("custom"));
  50. }
  51. render() {
  52. const { init, setValue, reset } = this.field;
  53. return (
  54. <div className="demo">
  55. <Custom {...init("custom", { initValue: ["test"] })} />
  56. <br />
  57. <br />
  58. <Button type="primary" onClick={this.onGetValue.bind(this)}>
  59. getValue
  60. </Button>
  61. <Button
  62. type="primary"
  63. onClick={() => setValue("custom", ["test", "setValue"])}
  64. >
  65. setValue
  66. </Button>
  67. <Button onClick={() => reset()}>reset</Button>
  68. </div>
  69. );
  70. }
  71. }
  72. ReactDOM.render(<App />, mountNode);
  1. .demo .next-btn {
  2. margin-right: 5px;
  3. }
  4. .custom {
  5. border: 1px dashed;
  6. padding: 4px;
  7. display: inline-block;
  8. }
  9. .custom span {
  10. border: 1px solid green;
  11. padding: 0px 5px;
  12. height: 24px;
  13. display: inline-block;
  14. margin-right: 2px;
  15. }

组合使用

很多组件

Field 表单数据获取、校验工具 - 图4

查看源码在线预览

  1. import {
  2. Button,
  3. Checkbox,
  4. Radio,
  5. Select,
  6. Range,
  7. DatePicker,
  8. TimePicker,
  9. Field
  10. } from "@icedesign/base";
  11. const { Group: CheckboxGroup } = Checkbox;
  12. const { Group: RadioGroup } = Radio;
  13. const list = [
  14. {
  15. value: "apple",
  16. label: "苹果"
  17. },
  18. {
  19. value: "pear",
  20. label: "梨"
  21. },
  22. {
  23. value: "orange",
  24. label: "橙子"
  25. }
  26. ];
  27. const layout = {
  28. marginBottom: 10,
  29. width: 400
  30. };
  31. class App extends React.Component {
  32. field = new Field(this, {
  33. deepReset: true
  34. });
  35. render() {
  36. const init = this.field.init;
  37. return (
  38. <div className="demo">
  39. <Select {...init("select", { initValue: "lucy" })} style={layout}>
  40. <li value="jack">jack</li>
  41. <li value="lucy">lucy</li>
  42. <li value="disabled" disabled>
  43. disabled
  44. </li>
  45. <li value="hugohua">hugohua</li>
  46. </Select>
  47. <br />
  48. <Range
  49. style={{ ...layout, marginTop: 30 }}
  50. slider={"double"}
  51. scales={10}
  52. marks={10}
  53. {...init("range", { initValue: [20, 40] })}
  54. />
  55. <div style={{ marginBottom: 10 }}>
  56. <CheckboxGroup
  57. dataSource={list}
  58. {...init("checkboxgroup", { initValue: ["apple"] })}
  59. />
  60. </div>
  61. <div style={{ marginBottom: 10 }}>
  62. <RadioGroup {...init("radiogroup", { initValue: "b" })}>
  63. <Radio value="a">A</Radio>
  64. <Radio value="b">B</Radio>
  65. <Radio value="c">C</Radio>
  66. <Radio value="d">D</Radio>
  67. </RadioGroup>
  68. </div>
  69. <div style={{ marginBottom: 10 }}>
  70. <DatePicker />
  71. </div>
  72. <div style={{ marginBottom: 10 }}>
  73. <DatePicker.RangePicker />
  74. </div>
  75. <div style={{ marginBottom: 10 }}>
  76. <TimePicker />
  77. </div>
  78. <Button
  79. type="primary"
  80. onClick={() => {
  81. console.log(this.field.getValues());
  82. }}
  83. >
  84. getValues
  85. </Button>
  86. <Button
  87. onClick={() => {
  88. this.field.setValues({
  89. select: "hugohua",
  90. range: [30, 50],
  91. checkboxgroup: ["orange"],
  92. radiogroup: "d"
  93. });
  94. }}
  95. >
  96. setValues
  97. </Button>
  98. <Button
  99. onClick={() => {
  100. this.field.reset();
  101. }}
  102. >
  103. reset
  104. </Button>
  105. </div>
  106. );
  107. }
  108. }
  109. ReactDOM.render(<App />, mountNode);
  1. .demo .next-btn {
  2. margin-right: 5px;
  3. }

自定义数据获取

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

Field 表单数据获取、校验工具 - 图5

查看源码在线预览

  1. import { Button, DatePicker, Upload, Field } from "@icedesign/base";
  2. class App extends React.Component {
  3. field = new Field(this);
  4. normFile(list) {
  5. if (Array.isArray(list)) {
  6. return list;
  7. }
  8. return list && list.fileList;
  9. }
  10. normDate(date, strdate) {
  11. console.log("normDate:", date, strdate);
  12. return strdate;
  13. }
  14. render() {
  15. const init = this.field.init;
  16. return (
  17. <div>
  18. <DatePicker
  19. {...init("datepicker", {
  20. getValueFromEvent: this.normDate
  21. })}
  22. />
  23. <br />
  24. <br />
  25. <Upload
  26. listType="text"
  27. {...init("upload", {
  28. getValueFromEvent: this.normFile
  29. })}
  30. />
  31. <br />
  32. <br />
  33. <Button
  34. type="primary"
  35. onClick={() => {
  36. console.log(this.field.getValues());
  37. }}
  38. >
  39. getValues
  40. </Button>
  41. </div>
  42. );
  43. }
  44. }
  45. ReactDOM.render(<App />, mountNode);

关联控制

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

Field 表单数据获取、校验工具 - 图6

查看源码在线预览

  1. import { Input, Select, Range, Field } from "@icedesign/base";
  2. class App extends React.Component {
  3. field = new Field(this, {
  4. onChange: (name, value) => {
  5. switch (name) {
  6. case "input":
  7. this.field.setValue("sync", `被改成了: ${value}`);
  8. break;
  9. case "select":
  10. this.field.setValue("sync", `${value} 来了`);
  11. break;
  12. case "range":
  13. this.field.setValue("sync", `坐标 (${value.join(",")}) ready`);
  14. break;
  15. }
  16. }
  17. });
  18. render() {
  19. const init = this.field.init;
  20. const layout = {
  21. marginBottom: 10,
  22. width: 400
  23. };
  24. return (
  25. <div>
  26. <Input
  27. placeholder="我在Field的onChange里面做了控制"
  28. {...init("input")}
  29. style={layout}
  30. />
  31. <br />
  32. <Input placeholder="受控同步" {...init("input")} style={layout} />
  33. <br />
  34. <Select style={layout} {...init("select", { initValue: "lucy" })}>
  35. <li value="jack">jack</li>
  36. <li value="lucy">lucy</li>
  37. <li value="disabled" disabled>
  38. disabled
  39. </li>
  40. <li value="hugo">hugo</li>
  41. </Select>
  42. <br />
  43. <Range
  44. style={{ ...layout, marginTop: 30 }}
  45. slider={"double"}
  46. scales={10}
  47. marks={10}
  48. {...init("range", { initValue: [20, 40] })}
  49. />
  50. <br />
  51. <hr style={{ marginBottom: 10 }} />
  52. <Input
  53. placeholder="我就是被人打的波波, 谁都能控制我"
  54. {...init("sync")}
  55. style={layout}
  56. />
  57. <br />
  58. </div>
  59. );
  60. }
  61. }
  62. ReactDOM.render(<App />, mountNode);

redux中使用

在redux中使用, 在componentWillReceiveProps更新

Field 表单数据获取、校验工具 - 图7

查看源码在线预览

  1. import { Input, Button, Field } from "@icedesign/base";
  2. import { combineReducers, createStore } from "redux";
  3. import { Provider, connect } from "react-redux";
  4. function formReducer(state = { email: "frankqian@qq.com" }, action) {
  5. switch (action.type) {
  6. case "save_fields":
  7. return {
  8. ...state,
  9. ...action.payload
  10. };
  11. default:
  12. return state;
  13. }
  14. }
  15. class Demo extends React.Component {
  16. static propTypes = {
  17. email: React.PropTypes.string,
  18. dispatch: React.PropTypes.func
  19. };
  20. componentWillReceiveProps(nextProps) {
  21. this.field.setValues({
  22. email: nextProps.email,
  23. newlen: nextProps.email.length
  24. });
  25. }
  26. field = new Field(this, {
  27. onChange: (name, value) => {
  28. console.log("onChange", name, value);
  29. this.field.setValue("newlen", value.length);
  30. this.props.dispatch({
  31. type: "save_fields",
  32. payload: {
  33. [name]: value
  34. }
  35. });
  36. }
  37. });
  38. setEmail() {
  39. this.props.dispatch({
  40. type: "save_fields",
  41. payload: {
  42. email: "qq@gmail.com"
  43. }
  44. });
  45. }
  46. render() {
  47. const init = this.field.init;
  48. const newLen = init("newlen", { initValue: this.props.email.length });
  49. return (
  50. <div>
  51. <Input
  52. {...init("email", {
  53. initValue: this.props.email,
  54. rules: [
  55. {
  56. required: true,
  57. type: "email",
  58. message: "用户名至少为 5 个字符"
  59. }
  60. ]
  61. })}
  62. />
  63. 现在的长度是:{newLen.value}
  64. <p>email: {this.props.email}</p>
  65. <Button onClick={this.setEmail.bind(this)}>set</Button>
  66. </div>
  67. );
  68. }
  69. }
  70. const ReduxDemo = connect(state => {
  71. return {
  72. email: state.formReducer.email
  73. };
  74. })(Demo);
  75. const store = createStore(
  76. combineReducers({
  77. formReducer
  78. })
  79. );
  80. ReactDOM.render(
  81. <Provider store={store}>
  82. <div>
  83. <ReduxDemo />
  84. </div>
  85. </Provider>,
  86. mountNode
  87. );

自定义错误

自己控制组件的errors

Field 表单数据获取、校验工具 - 图8

查看源码在线预览

  1. import { Input, Button, Field } from "@icedesign/base";
  2. class App extends React.Component {
  3. field = new Field(this);
  4. render() {
  5. const { init, getError, setError, setErrors } = this.field;
  6. return (
  7. <div className="demo">
  8. <Input
  9. {...init("input", {
  10. rules: {
  11. required: true,
  12. pattern: /hello/,
  13. message: "我是真正的错误信息,必须填写hello"
  14. }
  15. })}
  16. />
  17. <br />
  18. <span style={{ color: "red" }}>{getError("input")}</span>
  19. <br />
  20. <Button
  21. onClick={() => {
  22. setError("input", "设置的错误信息");
  23. }}
  24. >
  25. setError
  26. </Button>
  27. <Button
  28. onClick={() => {
  29. setErrors({ input: "设置的错误信息2" });
  30. }}
  31. >
  32. setErrors
  33. </Button>
  34. <Button
  35. onClick={() => {
  36. setErrors({ input: "" });
  37. }}
  38. >
  39. clear
  40. </Button>
  41. <br />
  42. <br />
  43. <Input {...init("input2")} />
  44. <br />
  45. <span style={{ color: "red" }}>{getError("input2")}</span>
  46. <br />
  47. <Button
  48. onClick={() => {
  49. setError("input2", "设置的错误信息onChange后会被去除");
  50. }}
  51. >
  52. setError
  53. </Button>
  54. </div>
  55. );
  56. }
  57. }
  58. ReactDOM.render(<App />, mountNode);
  1. .demo .next-btn {
  2. margin-right: 5px;
  3. }

获取对象或数组

init('arr.0') 的数据转换成 obj={arr:['']};把 init('a.b') 的数据转换成 obj={a:{b:'value'}}

Field 表单数据获取、校验工具 - 图9

查看源码在线预览

  1. import { Input, Button, Field } from "@icedesign/base";
  2. class App extends React.Component {
  3. field = new Field(this, {
  4. parseName: true // 这里打开开关
  5. });
  6. onGetValue() {
  7. console.log(this.field.getValues());
  8. }
  9. onSetValue() {
  10. this.field.setValues({
  11. a: {
  12. b: "b",
  13. c: "c"
  14. },
  15. arr: ["first", "second"]
  16. });
  17. }
  18. render() {
  19. const { init, reset } = this.field;
  20. return (
  21. <div className="demo">
  22. <h2>对象转换</h2>
  23. <Input {...init("a.b", { initValue: "test1" })} /> &nbsp;
  24. <Input {...init("a.c", { initValue: "test2" })} />
  25. <br />
  26. <h2>数组转换</h2>
  27. <Input {...init("arr.0", { initValue: "0" })} /> &nbsp;
  28. <Input {...init("arr.1", { initValue: "1" })} />
  29. <br />
  30. <br />
  31. 结构化数据:
  32. <pre>{JSON.stringify(this.field.getValues(), null, 2)}</pre>
  33. <br />
  34. <br />
  35. <Button type="primary" onClick={this.onGetValue.bind(this)}>
  36. getValues
  37. </Button>
  38. <Button onClick={this.onSetValue.bind(this)}>setValues</Button>
  39. <Button onClick={() => reset()}>reset</Button>
  40. </div>
  41. );
  42. }
  43. }
  44. ReactDOM.render(<App />, mountNode);
  1. .demo .next-btn {
  2. margin-right: 5px;
  3. }

校验

注意:Form和Field做了深度结合,在Form中使用Field,错误信息不需getError获取会自动展现。校验的错误信息需要用getError获取

Field 表单数据获取、校验工具 - 图10

查看源码在线预览

  1. import { Input, Button, Checkbox, Field } from "@icedesign/base";
  2. const CheckboxGroup = Checkbox.Group;
  3. const list = [
  4. {
  5. value: "apple",
  6. label: "苹果"
  7. },
  8. {
  9. value: "pear",
  10. label: "梨"
  11. },
  12. {
  13. value: "orange",
  14. label: "橙子"
  15. }
  16. ];
  17. class App extends React.Component {
  18. state = {
  19. checkboxStatus: true
  20. };
  21. field = new Field(this, { scrollToFirstError: true });
  22. isChecked(rule, value, callback) {
  23. if (!value) {
  24. callback("没有勾选同意协议");
  25. } else {
  26. callback();
  27. }
  28. }
  29. userName(rule, value, callback) {
  30. if (value === "frank") {
  31. setTimeout(() => callback("名称已经存在"), 200);
  32. } else {
  33. setTimeout(() => callback(), 200);
  34. }
  35. }
  36. render() {
  37. const init = this.field.init;
  38. return (
  39. <div className="demo">
  40. <Input
  41. {...init("input", {
  42. initValue: "删除试试",
  43. rules: { required: true }
  44. })}
  45. />
  46. {this.field.getError("input") ? (
  47. <span style={{ color: "red" }}>
  48. {this.field.getError("input").join(",")}
  49. </span>
  50. ) : (
  51. ""
  52. )}
  53. <br />
  54. <br />
  55. <Input
  56. placeholder="离开焦点onBlur"
  57. {...init("input1", {
  58. rules: {
  59. required: true,
  60. message: "不能为空",
  61. trigger: ["onBlur", "onChange"]
  62. }
  63. })}
  64. />
  65. {this.field.getError("input1") ? (
  66. <span style={{ color: "red" }}>
  67. {this.field.getError("input1").join(",")}
  68. </span>
  69. ) : (
  70. ""
  71. )}
  72. <br />
  73. <br />
  74. <Input
  75. defaultValue=""
  76. placeholder="填写frank"
  77. {...init("username", {
  78. rules: {
  79. validator: this.userName,
  80. trigger: ["onBlur", "onChange"]
  81. }
  82. })}
  83. />
  84. {this.field.isValidating("username") ? "正在校验中..." : ""}
  85. {this.field.getError("username") ? (
  86. <span style={{ color: "red" }}>
  87. {this.field.getError("username").join(",")}
  88. </span>
  89. ) : (
  90. ""
  91. )}
  92. <br />
  93. <br />
  94. 是否同意以上协议:
  95. <Checkbox
  96. {...init("checkbox", {
  97. valueName: "checked",
  98. rules: { validator: this.isChecked }
  99. })}
  100. />
  101. {this.field.getError("checkbox") ? (
  102. <span style={{ color: "red" }}>
  103. {this.field.getError("checkbox").join(",")}
  104. </span>
  105. ) : (
  106. ""
  107. )}
  108. <br />
  109. <br />
  110. <Input
  111. multiple
  112. maxLength={10}
  113. defaultValue="字符串长度在3-10之间"
  114. {...init("textarea", {
  115. rules: [
  116. {
  117. required: true,
  118. min: 3,
  119. max: 10
  120. }
  121. ]
  122. })}
  123. />
  124. {this.field.getError("textarea") ? (
  125. <span style={{ color: "red" }}>
  126. {this.field.getError("textarea").join(",")}
  127. </span>
  128. ) : (
  129. ""
  130. )}
  131. <br />
  132. <br />
  133. {this.state.checkboxStatus ? (
  134. <div>
  135. 数组类型的数据校验:
  136. <CheckboxGroup
  137. dataSource={list}
  138. {...init("checkboxgroup", {
  139. rules: {
  140. required: true,
  141. type: "array",
  142. message: "必须勾选一个吧"
  143. }
  144. })}
  145. style={{ marginBottom: 10 }}
  146. />
  147. {this.field.getError("checkboxgroup") ? (
  148. <span style={{ color: "red" }}>
  149. {this.field.getError("checkboxgroup").join(",")}
  150. </span>
  151. ) : (
  152. ""
  153. )}
  154. </div>
  155. ) : null}
  156. <br />
  157. <br />
  158. <Button
  159. type="primary"
  160. onClick={() => {
  161. this.field.validate((errors, values) => {
  162. console.log(errors, values);
  163. });
  164. }}
  165. >
  166. validate
  167. </Button>
  168. <Button
  169. onClick={() => {
  170. this.field.reset();
  171. }}
  172. >
  173. reset
  174. </Button>
  175. <Button
  176. onClick={() => {
  177. if (this.state.checkboxStatus) {
  178. this.setState({ checkboxStatus: false });
  179. this.field.remove("checkboxgroup");
  180. } else {
  181. this.setState({ checkboxStatus: true });
  182. }
  183. }}
  184. >
  185. {this.state.checkboxStatus ? "delete" : "restore"}
  186. </Button>
  187. </div>
  188. );
  189. }
  190. }
  191. ReactDOM.render(<App />, mountNode);
  1. .demo .next-btn {
  2. margin-right: 5px;
  3. }

自定义受控字段

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

Field 表单数据获取、校验工具 - 图11

查看源码在线预览

  1. import { Button, Checkbox, Radio, Switch, Field } from "@icedesign/base";
  2. class App extends React.Component {
  3. field = new Field(this);
  4. render() {
  5. const init = this.field.init;
  6. return (
  7. <div className="demo">
  8. <Radio {...init("radio", { initValue: false, valueName: "checked" })}>
  9. {" "}
  10. checked
  11. </Radio>
  12. <br />
  13. <Checkbox
  14. {...init("checkbox", { initValue: true, valueName: "checked" })}
  15. >
  16. defaultChecked
  17. </Checkbox>
  18. <br />
  19. <Switch
  20. {...init("switch", { initValue: false, valueName: "checked" })}
  21. style={{ marginTop: 10, marginBottom: 10 }}
  22. />
  23. <br />
  24. <Button
  25. type="primary"
  26. onClick={() => {
  27. console.log(this.field.getValues());
  28. }}
  29. >
  30. getValues
  31. </Button>
  32. <Button
  33. onClick={() => {
  34. this.field.setValues({
  35. radio: true,
  36. switch: true,
  37. checkbox: false
  38. });
  39. }}
  40. >
  41. {" "}
  42. setValues{" "}
  43. </Button>
  44. <Button
  45. onClick={() => {
  46. this.field.reset();
  47. }}
  48. >
  49. reset
  50. </Button>
  51. </div>
  52. );
  53. }
  54. }
  55. ReactDOM.render(<App />, mountNode);
  1. .demo .next-btn {
  2. margin-right: 5px;
  3. }

相关区块

Field 表单数据获取、校验工具 - 图12

暂无相关区块