From表单的检验
是前端绕不开的话题,使用Antd
的时候,其自带的表单会带有校验功能,但是在某些情况下是不能满足我们的需求的,这种情况下,我们就需要自定义一些校验。
我需要在表单中校验这么一个组件,组件中包含了三个下拉框,需要对三个下拉框中的值进行联合校验,那么它不是简单地表单项校验,就需要额外的自己去定义这个复杂的表单项的校验。最终实现的效果应该是这样:
在表单提交,或者选项值发现变化的时候,需要去自动校验是否符合规则。
在Antd
官网上提到了这么一种关于复杂组件的自定义校验方式戳这里
其中提到:
自定义或第三方的表单控件,也可以与 Form 组件一起使用。只要该组件遵循以下的约定:
- 提供受控属性
value
或其它与valuePropName
的值同名的属性。- 提供
onChange
事件或trigger
的值同名的事件。
这么看来官方是支持我们去校验第三方组件的,只要遵循它的约定即可。官方给出的示例代码中是可以直接拿来用的,那我为什么还要在这里强调呢?
因为在组件调用时,时常会出现参数传递的情况,那么我们就需要将父组件的参数传递过来,这点是官方没有提到的,如下:
const PriceInput = ({
value = {
}, onChange }) => {
}
如果你不需要额外的参数传递的话,那么可以这么直接这么搞。但是如果牵扯到数据传递比如说下拉框,列表等其他需要数据准备的控件就需要你从父组件中传递额外的参数了。
最初我的设想是这样的
// 自定义校验组件
const RemoteCheck = (props, {
value = {
}, onChange }) => {
}
但是在使用到triggerChange
触发change
事件的时候,就会出现onChange
未定义的情况,而报错。
仔细想了一下,觉得组件的传递数据,包含自定义参数与第三方组件的参数都应该所属于props
,因为无论是什么组件,在react
中必须要遵守单向数据流
的形式:即父组件可以通过props向子组件传递参数
。
父组件引用子组件代码:
<LocalCheck roletags={roletags} workloads={workloads} direction={direction} ruletype={ruletype}/>
那么我们在子组件中简单的打印一下props
就会发现端倪:
可以看到,onChange
函数是挂载在props
上的,基于此我们就可以正常的使用props
传参和使用表单自带的callback函数。
- onChange:
callback函数
,当触发时将value
值绑定到表单项中的绑定值上- value:表单项的绑定值
这个绑定值,我们需要在Form
表单中初始化的时候去绑定:
<Form
{
...layout}
ref={
form => this.form = form}
onFinish={
this.handleSubmit}
labelAlign="right"
initialValues={
data}
>
</Form>
比如说我这里绑定的是data
,data
中有个属性为local
,local
中就是绑定的表单项的属性,而你实际自定义组件值应该绑定到local
中。
this.state = {
data: {
local: {
roletag: [], workload: [], ipobject: [] } }, // 用于回显数据
}
而在表单上需要将data中的local绑定到name上
<Form.Item
{...layout}
label={ styleName="local-detail">本端span>}
name="local"
rules={
[
{
validator: (_, value) => {
console.log("_value", value)
},
},
]
}
>
<LocalCheck roletags={roletags} workloads={workloads} direction={direction} ruletype={ruletype}/>
Form.Item>
子组件可以参考官网上的demo来实现,由于是公司的代码,我就不完全放上了,说一下需要注意的地方
1.从props
中获取需要的参数以及onChange
和value
const {
roletags, workloads, onChange, value, direction, ruletype } = props
2.定义你需要的绑定的数据(比如我是两下拉菜单,我需要将他们的value值分别绑定为roletag和workload,那么需要先定义这两个数据),将他们分别绑定到seelct
的value上
const [workload, setWorkload] = useState(value.workload);
const [roletag, setRole] = useState(value.roletag);
3.将定义的数据绑定到callback函数中
const triggerChange = (changedValue) => {
onChange({
roletag,
workload,
...value,
...changedValue
})
};
4.当下拉菜单触发onchange
事件时调用triggerChange
,并将值传递给它
// onchange触发的时间
const changeR = (svalue) => {
// 调用触发器
triggerChange({
roletag: svalue })
}
5.更新value
中的值,因为我们需要将新的数据值传给父组件,所以需要更新value
// onchange触发的时间
const changeR = (svalue) => {
// 调用触发器
triggerChange({
roletag: svalue })
value.roletag = svalue
}
6.在父组件中通过Form.Item
的rules
来校验组件
rules={
[
{
validator: (_, value) => {
console.log("_value", value)
}
},
]
}
7.查看打印输出值
可以看到在value
中确实获取到数据,那么当我们提交表单的时候,就能在values
中拿到local
对应的值。你可以在rules
去定义自己需要的校验规则即可。
自定义的组件应该只负责数据的输出和一些逻辑控制,不负责校验相关的东西。需要自定义校验规则,请在父组件中实现。
至此一个自定义的组件表单校验就完成了。