今天我们就来看看怎么基于rc-form做一个验证rules规则的组件。

最终效果图如下所示:


领用人和申请部门都是必填项,如果提交数据的时候没有选择的话则给出第一个错误提示,【比如俩个都不符合规则那么只报第一个错误】。并且不符合规则的那一项变红。不符合规则的改变时对应的状态消失。


接下来我们看一下我们最终实现的样式:

1.初始样式:

使用rc-form做个验证不符合rules规则的组件_自己做form

2.提交验证时:

使用rc-form做个验证不符合rules规则的组件_form组件实现_02

3.选择数据后【只是选择了数据并没有点击提交数据重新验证】

使用rc-form做个验证不符合rules规则的组件_form组件实现_03

4.全部符合规则提交时


有人可能会奇怪笔者的这个返回来的为什么是个数组。。。因为那俩个是笔者自己做的组件,可单选可多选。为了方便所以就弄了个数组。


使用rc-form做个验证不符合rules规则的组件_组件搭建_04




接下来看一下我们的组件:


笔者没有把样式什么的都做出来,只是把关键的逻辑代码做出来了,里面都是有注释的。


Form组件:

import React, { useEffect } from 'react';
import {
Picker, List,
} from 'antd-mobile'; // 笔者只是借用下antd-mobile的选择器组件,你自行使用自己的组件库
import {isExist, isFunction} from "../../utils/fn";
import {getInput} from "../../utils/box"; // 除了上面俩个特殊要求的组件其余的比如选日志或者底部弹出选择一些东西都可以用antd-mobile【你们自己公司用的什么组件库你就到那里去找】里面提供的组件进行使用。只不过可能需要改写一下样式。

/**
* Form组件
* @param form 必须传入
* @param columns 【自己约定规则】
* */
function Index({
form,
columns = [],
}) {
// 如果父组件没传过来form给个错误提示,这样其他人用你组件也就知道了,或者使用ts或者propTypes等定义你的类型
useEffect(() => {
if (!form) alert('请传入form!!!!!!!!!!!!!!!!');
}, []);

function renderItem(item = {}, form) {
// 根据item规则渲染你的组件,从form里结构出getFieldProps||getFieldDecorator进行使用。
// 比如我们使用getFieldProps
// 做一个判断比如说是select组件:
if (item.selectData) {
// 笔者在这里演示定义的columns大概是这样的:
// {id: 'xxx', label: 'xxx', selectData: [], rules: []}
// id需要是唯一的,并且我们在提交表单数据及校验的时候也是使用id
// label就是我们左侧的文字。
// selectData是要选择的数据
// rules就是你要定义的规则
return (
<Picker
data={item.selectData}
{...getFieldProps(item.id, {
rules: item.rules,
})}
className="forss"
>
<List.Item arrow="horizontal">{item.label}</List.Item>
</Picker>
);
}
// 可以引入外部的一个方法或者重新定义一个方法去做这些判断,这样这里的代码能更简洁些。笔者这里只是做个演示就没有提出去了。
// 这里笔者就随便把label返回回去了,你可以自己判断如果不满足你的任何约束的内容该不该返回,或者没约束的时候默认返回什么类型的表单元素。全都看你自己。
return item.label;
}

// 如果columns不是数组的话返回一个null;
if (Array.isArray(columns)) return null;

// 关键代码
const { getFieldsError } = form;
// 把我们columns遍历一遍并将id返回给一个names里。
const names = columns.map(item => item.id);
// 传入给getFieldsError参数names【我们在上一行代码中刚处理过的集合】
// 这样就能获取到当前不符合rules规则的有哪一项了。返回回来的结果是object
const errorFields = getFieldsError(names) || {};
const errorArr = []; // 存储不符合rules的key集合
// 用for in遍历obj。关于for in的使用不会的可以自行百度或者到笔者博客里看。
for (const ite in errorFields) {
// 当这一项有错误时会返回一个error数组,没错误会返回undefined。
// 如果你的项目没有配置支持?.的写法请自行判断非的情况。如下:
// errorFields[ite] && errorFields[ite].length > 0
if (errorFields[ite]?.length > 0) {
errorArr.push(ite);
}
}

return (
<form>
{columns.map(item => (
<div
key={item.id}
style={{
// 如果errorArr里包含当前的id那么就给他颜色变红
color: `${errorArr.includes(item.id) ? 'red' : ''}`,
}}
>
// 定义一个方法或者在做一个组件,根据你自己定义的columns规则渲染子组件。
{renderItem(item, form)}
</div>
))}
</form>
);
}

export default Index;

父组件使用Form组件时:

import React from 'react';
import { createForm } from 'rc-form';
import { Toast } from 'antd-mobile';
import { Form } from '../newComponents';

function Index(props) {
// 定义一个方法返回错误信息,一般放在公共方法文件里,因为很多地方用到form就会用到它。
// 只返回第一个错误的错误信息
function getFormValidatorErrText(error = {}) {
for (let key in error) {
if (error[key]?.errors?.length > 0) {
return error[key]?.errors[0].message;
}
}
return '未知问题!';
}

return (
<div>
<Form
form={props.form}
columns={[
{
id: 'consumerUserId',
label: '领用人',
selectData: [{id: 1, title: '我是1'}, {id: 2, title: '我是2'}],
// 一般required可以单独放在外面,因为他经常用,而且返回的错误信息大概都是这个模板的,所以我们可以统一在Form组件里处理。不会弄的朋友可以私信笔者或者下方评论
rules: [
{ required: true, message: '领用人不能为空' }
],
},
]}
/>
<br />
<br />
<button onClick={() => {
props.form.validateFields({ force: true }, (error) => {
if (!error) { // 没有错误的话我们就可以根据form数据进行提交了
console.log(props.form.getFieldsValue());
} else {
// 有错误的话那就进行错误处理
Toast.info(getFormValidatorErrText(error));
}
});
}}
style={{
height: '30px',
lineHeight: '30px',
textAlign: 'center',
width: '100%',
border: '1px solid',
}}
>提交数据
</button>
</div>
);
}

export default createForm()(Index);

这样我们的上述需求都实现了,不知道朋友们学到了没有呢?


有些朋友可能不知道哪里实现的当我们选择值的时候将它的error错误样式取消的。我们是利用了一个机制,当数据变化的时候react会将有变动的组件进行更新,这样我们在form组件里获取的那个getFieldsError就可以从新进行看哪个是验证有错误的,没错误的自然就恢复原样式了~