今天我們就來看看怎麼基於rc-form做一個驗證rules規則的組件。
最終效果圖如下所示:
領用人和申請部門都是必填項,如果提交數據的時候沒有選擇的話則給出第一個錯誤提示,【比如倆個都不符合規則那麼只報第一個錯誤】。並且不符合規則的那一項變紅。不符合規則的改變時對應的狀態消失。
接下來我們看一下我們最終實現的樣式:
1.初始樣式:
2.提交驗證時:
3.選擇數據後【只是選擇了數據並沒有點擊提交數據重新驗證】
4.全部符合規則提交時
有人可能會奇怪筆者的這個返回來的爲什麼是個數組。。。因爲那倆個是筆者自己做的組件,可單選可多選。爲了方便所以就弄了個數組。
接下來看一下我們的組件:
筆者沒有把樣式什麼的都做出來,只是把關鍵的邏輯代碼做出來了,裏面都是有註釋的。
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就可以從新進行看哪個是驗證有錯誤的,沒錯誤的自然就恢復原樣式了~