Form
业务场景中,我们会经常使用Form进行一些数据收集的工作。这一章,我们会实现一个简单的 Form 用来收集数据,并与后端通信进行传输。
首先看一下我们这一章需要实现的 Form 是什么样的:
Form demo表单绑定数据源。
从上面的内容可以看出来,有必输字段,也有需要进行特殊校验的字段,如手机号,同时也会出现带后缀或者前缀的字段。
接下来,我们从 DataSet 的构建开始,一步步构建一个最为简单的 Form。
构建 DataSet
首先,我们需要为了这个 Form 构造一个简单的 DataSet 收集数据:
// DataSet.js
const FormDataSet = {
// DataSet 不和后端交互时,自动新建一条数据,在表单场景下比较常见
autoCreate: true,
fields: [
// 这里是与后端约定的,上传时用到的字段
{ name: 'phone', type: 'string', label: '手机号' },
{ name: 'password', type: 'string', label: '密码' },
{ name: 'confirmPassword', type: 'string', label: '确认密码' },
{ name: 'age', type: 'number', label: '年龄' },
{ name: 'sex', type: 'string', label: '性别' },
{ name: 'language', type: 'string', label: '语言' },
{ name: 'email', type: 'string', label: '邮箱' },
{ name: 'homePage', type: 'string', label: '个人主页' },
{ name: 'birth', type: 'date', label: '生日' },
],
transport: {
// 创建时 DataSet 将会调用的方法
// url 随便找的,可以自己替换
// create / read / update / destroy 都可以等量替换成函数,create 涉及到上传新创建的数据,因此需要用到 data
create: ({ data, params, dataSet }) => {
console.log(data+" ", params+" ", dataSet.toJSONData());
return ({
// url: 'v1/projects/${projectId}',
// method: 'post',
// data,
})
}
},
events: {
load: ({ dataSet }) => {
console.log('加载完成', dataSet)
}
}
};
export default FormDataSet;
接下来我们再看看需要实现的 Form,这里可以发现有几个需要注意的点:
- 性别、语言是多选框 / 下拉框,而这几项存在两种写法,这里我们介绍绑定数据源的写法。
- 手机号本身存在特殊的校验,需要我们在 field 内对字段进行相应的配置
首先来看看第一个问题。
绑定数据源的形式实现多选 / 下拉选择
绑定数据源实现多选 / 下拉的主要优势在于,如果这两个字段以后需要从后端获取多选 / 下拉值的时候,我们不需要对渲染的代码进行过多的改造即可实现。实际上,我们只需要为这两个下拉框新建两个 DataSet 即可。
首先,为性别和语言分别新建两个 DataSet 构造对象,分别叫做 sexOptionDataSet 与 languageOptionDataSet。
// sexOptionDataSet.js
const sexOptionDataSet = {
fields: [
// 这里的字段配置,实际上是根据我们自己的需求虚拟的
// 实际上,如果从后端读取值的话,还是要按照后端的规范来写
{ name: 'text', type: 'string' },
{ name: 'value', type: 'string' },
],
// 因为我们的需求比较简单,因此直接用 data 生成本地假数据即可
data: [{
text: '男',
value: 'male',
}, {
text: '女',
value: 'female',
}],
};
export default sexOptionDataSet;
// languageOptionDataSet.js
// 与上面那个构造对象是同样的道理
const languageOptionDataSet = {
fields: [
{ name: 'text', type: 'string' },
{ name: 'value', type: 'string' },
],
data: [{
text: '简体中文',
value: 'zh-cn',
}, {
text: '英语(美国)',
value: 'en-us',
}, {
text: 'japanese',
value: 'ja-jp',
}],
};
export default languageOptionDataSet;
然后,我们修改一下之前生成的那个 DataSet,将我们新创建的两个 optionDataSet 传进去并进行构建。
// DataSet.js
import { DataSet } from 'choerodon-ui/pro';
import SexOptionDataSet from './sexOptionDataSet';
import LanguageOptionDataSet from './languageOptionDataSet';
const sexOptionDataSet = new DataSet(SexOptionDataSet);
const languageOptionDataSet = new DataSet(LanguageOptionDataSet);
const FormDataSet = {
autoCreate: true,
fields: [
{ name: 'phone', type: 'string', label: '手机号' },
{ name: 'password', type: 'string', label: '密码' },
{ name: 'confirmPassword', type: 'string', label: '确认密码' },
{ name: 'age', type: 'number', label: '年龄' },
// textField 指的是,下层的 options 中被指定用于显示选项名称的字段,这里我们已经定成 text 了
// 同理,valueField 指下层 options 中被指定用于传输给后端的值,这里我们指定为 value
{ name: 'sex', type: 'string', label: '性别', textField: 'text', valueField: 'value', options: sexOptionDataSet },
{ name: 'language', type: 'string', label: '语言', textField: 'text', valueField: 'value', options: languageOptionDataSet },
{ name: 'email', type: 'string', label: '邮箱' },
{ name: 'homePage', type: 'string', label: '个人主页' },
{ name: 'birth', type: 'date', label: '生日' },
],
transport: {
create: ({ data, params, dataSet }) => {
console.log(data+" ", params+" ", dataSet.toJSONData());
return ({
// url: 'v1/projects/${projectId}',
// method: 'post',
// data,
})
}
},
events: {
load: ({ dataSet }) => {
console.log('加载完成', dataSet)
}
}
};
export default FormDataSet;
接下来,Form 的初期准备工作就完成了,我们可以开始写渲染层的代码了。 Form 需要的组件比较多,比如用于数字输入的 NumberField,用于日期选取的 DatePicker 之类的,我们逐一进行引入。
// Table.jsx
import React from 'react';
import FormDS from './DataSet';
import {
DataSet,
Form,
TextField,
Password,
NumberField,
EmailField,
UrlField,
DatePicker,
Select,
SelectBox,
Button,
Menu,
Dropdown,
Icon,
} from 'choerodon-ui/pro';
class MyForm extends React.Component {
constructor(props) {
super(props);
this.formDataSet = new DataSet(FormDS);
}
// 这里需要注意一下,Form 能接收 record 和 dataSet 这两个属性二选一。
// 其中传入 dataSet 属性后,Form 会默认指向 DataSet 的 ds.current,默认是第一条
// 如果需要指定 dataSet 中的某条数据的话,请使用 record 属性
render() {
return (
<Form dataSet={this.formDataSet}>
<TextField name="phone" />
<Password name="password" />
<Password name="confirmPassword" />
<NumberField name="age" />
<SelectBox name="sex" />
<Select name="language" />
<EmailField name="email" />
<UrlField name="homePage" />
<DatePicker name="birth" />
<div>
<Button type="submit">注册</Button>
<Button type="reset" style={{ marginRight: 8 }}>重置</Button>
</div>
</Form>
)
}
}
export default MyForm;
可以看到,借助 DataSet 实现的表单,整体给人感觉非常清爽,负责数据交互的逻辑均被隐藏到了 DataSet 中。 接下来我们来处理第二个问题,如何对字段进行校验。
对字段进行校验
field 中存在三个字段,validator、pattern 和 required。这三个字段可以帮助我们进行字段的相关校验。
首先看手机号码的校验,手机号的校验非常容易找到,在网上稍微搜索一下就可以找得到,我们把它放到 pattern 中。
其次,每个字段都拥有必输校验,所以我们需要在每个字段上加上required = true
。
最后,确认密码字段存在需要与密码字段进行比对的需求,因此我们需要使用 validator 字段定义自定义函数,进行校验的自定义。
稍稍改造一下我们之前的 DataSet:
// DataSet.js
import { DataSet } from 'choerodon-ui/pro';
import SexOptionDataSet from './sexOptionDataSet';
import LanguageOptionDataSet from './languageOptionDataSet';
const sexOptionDataSet = new DataSet(SexOptionDataSet);
const languageOptionDataSet = new DataSet(LanguageOptionDataSet);
const FormDataSet = {
autoCreate: true,
fields: [
{ name: 'phone', type: 'string', label: '手机号', pattern: '1[0-9]{10}', required: true },
{ name: 'password', type: 'string', label: '密码', required: true },
{ name: 'confirmPassword', type: 'string', label: '确认密码', required: true, validator: (value, name, record) => {
// 这个地方能返回的不止有布尔类型和字符串类型,你也可以自己自行写一个 html 标签自定义样式,比如字体颜色改成蓝色
if (value !== record.get('password')) {
return '您两次输入的密码不一致,请重新输入';
}
return true;
} },
{ name: 'age', type: 'number', label: '年龄', required: true },
{ name: 'sex', type: 'string', label: '性别', textField: 'text', valueField: 'value', options: sexOptionDataSet, required: true },
{ name: 'language', type: 'string', label: '语言', textField: 'text', valueField: 'value', options: languageOptionDataSet, required: true },
{ name: 'email', type: 'string', label: '邮箱', required: true },
{ name: 'homePage', type: 'string', label: '个人主页', required: true },
{ name: 'birth', type: 'date', label: '生日', required: true },
],
transport: {
create: ({ data, params, dataSet }) => {
console.log(data+" ", params+" ", dataSet.toJSONData());
return ({
// url: 'v1/projects/${projectId}',
// method: 'post',
// data,
})
}
},
events: {
load: ({ dataSet }) => {
console.log('加载完成', dataSet)
}
}
};
export default FormDataSet;
这样我们就做好了一个最简单的表单,下一章我们会讲解如何利用 DataSet 构造一个简单的树。