表单是html的基础元素,接下来我会用React实现一个表单组件。支持包括输入状态管理,表单验证,错误信息展示,表单提交,动态表单元素等功能。
表单元素的输入状态管理,可以基于react state 实现。
const [formData, setFormData] = useState(initial_data);
在表单元素变更后,对变更结果进行验证,若验证失败,则更新失败状态,若验证成功,则更新数据状态, 并移除之前老的失败状态。
/**
* 表单错误状态
*/
const [errors, setErrors] = useState({});
/**
* 表单数据变更处理函数
*/
const setFieldData = (name, value) => {
// 进行参数校验
if (validators && validators[name]) {
const error = validators[name](value);
if (error) {
setErrors((errors) => ({...errors, [name]: error}));
return;
}
setErrors((errors) => {
const newErrors = {...errors};
delete newErrors[name];
return newErrors;
})
}
// 更新表单数据
setFormData({
...formData,
[name]: value
});
}
表单提交需要判断是否有校验失败错误,如果有的话提交失败,如果没有提交成功。
/**
* 表单提交处理函数
*/
const handleSubmit = (e) => {
e.preventDefault();
if (errors && Object.keys(errors).length > 0) {
console.log('表单校验未通过');
return;
}
if (submitFunc) {
console.log('开始执行提交函数');
submitFunc(formData);
}
}
表单项组件会根据参数不同的类型返回不同的组件,并且error和fieldData,setFieldData与父组件Form绑定。
/**
* 表单项组件
*/
const FormItem = ({name, type, error, label, fieldData, setFieldData}) => {
if (type === 'submit') {
return (
)
} else if (type === 'text') {
return (
setFieldData(name, e.target.value)}/>
{error && {error}}
)
} else if (type === 'password') {
return (
setFieldData(name, e.target.value)}/>
{error && {error}}
)
}
return null;
}
Form组件是基于React实现,并对表单form的功能进行日常封装。
import {useState} from "react";
/**
* 表单组件
* @param initial_data 初始数据
* @param validators 校验器
* @param submitFunc 提交函数
* @param children FormItem组件列表
*/
const Form = ({initial_data, validators, submitFunc, children}) => {
/**
* 表单数据状态
*/
const [formData, setFormData] = useState(initial_data);
/**
* 表单错误状态
*/
const [errors, setErrors] = useState({});
/**
* 表单数据变更处理函数
*/
const setFieldData = (name, value) => {
// 进行参数校验
if (validators && validators[name]) {
const error = validators[name](value);
if (error) {
setErrors((errors) => ({...errors, [name]: error}));
return;
}
setErrors((errors) => {
const newErrors = {...errors};
delete newErrors[name];
return newErrors;
})
}
// 更新表单数据
setFormData({
...formData,
[name]: value
});
}
/**
* 表单提交处理函数
*/
const handleSubmit = (e) => {
e.preventDefault();
if (errors && Object.keys(errors).length > 0) {
console.log('表单校验未通过');
return;
}
if (submitFunc) {
console.log('开始执行提交函数');
submitFunc(formData);
}
}
return (
<>
>
)
}
/**
* 表单项组件
*/
const FormItem = ({name, type, error, label, fieldData, setFieldData}) => {
if (type === 'submit') {
return (
)
} else if (type === 'text') {
return (
setFieldData(name, e.target.value)}/>
{error && {error}}
)
} else if (type === 'password') {
return (
setFieldData(name, e.target.value)}/>
{error && {error}}
)
}
return null;
}
export {Form, FormItem};
function App() {
return (
);
}