简单思路模拟处理表单数据
首先创建一个普通的form表单
//Login.jsx
import React,{Component} from 'react'
class Login extends Component {
render() {
return <div className='login'>
<div className='card'>
<input />
<input />
<button/>
</div>
</div>
}
}
我们需要一个高阶组件来强化这个form表单让它有验证和收集表单信息和提交表单的功能
1.首先创建一个Form的高阶函数,传入一个组件返回一个强化后的组件
//form.jsx
import React from 'react'
function Form(Comp){
return class extends React.Component{
render(){
return <Comp />
}
}
}
2.添加一个返回包装输入控件的高阶组件
//form.jsx
import React from 'react'
function Form(Comp){
return class extends React.Component {
_refs: any = {} //存放DOM节点
options: any = {}//存放选项
state: any = {}//存放表单字段
{/*为Form表单添加一个返回包装输入控件的高阶组件getFieldDec*/}
getFieldDec = (field, option) => {
this.options[field] = option//将规则存入
return (InputComp) => {//返回一个高阶函数来强化Input
!this._refs[field] && (this._refs[field] = React.createRef())//避免多次渲染DOM丢失
return <>
{
React.cloneElement(InputComp, {//vdom不能修改克隆一份再扩展
name: field,
value: this.state[field] || '',
onChange: this.handleChange,
ref: this._refs[field]
})
}
{//简单的验证信息提示
this.state[field + 'Message'] && <p className='message'>{this.state[field + 'Message']}</p>
}
</>
}
}
render(){
return <Comp getFieldDec={this.getFieldDec}/>//将getFieldDec挂载到组件上
}
}
}
3.添加change事件表单验证处理事件
//form.jsx
function Form(Comp: any) {
return class extends React.Component {
_refs: any = {} //存放DOM节点
options: any = {}//存放选项
state: any = {}//存放表单字段
handleChange = (e: any) => {
let { name, value } = e.target;
this.setState({ [name]: value}, () => {
// 校验
this.validateField(name)
})
}
getFieldDec = (field, option) => {
....
}
validateField = (field) => {
const rules = this.options[field].rules//取到对应的配置选项
const ret = !rules.some((rule) => {// 只要有任何一项校验失败就返回true跳出,对返回值取反表示校验失败
if (rule.required) {//当存在必填执行
if (!this.state[field]) {//当检测到为空执行
this.setState({ [field + 'Message']: rule.message || '此项必填' })
this._refs[field].current.focus()//焦点选中验证失败的dom
return true
}
}
})
ret && this.setState({ [field + 'Message']: "" })//当验证通过清空提示
return ret //返回一个验证是否通过的boolean值
}
//批量验证表单获取状态
validateFields = (callback) => {//传入一个回调函数
let values = {}//声明一个空对象为了排除不必要的一些数据
const rets = Object.keys(this.options).every((field) => {//遍历配置进行验证假如有一项不满足就会返回false
values[field] = this.state[field] //我们只需要他的value不需要message
return this.validateField(field) //执行验证
})
callback(rets, values)//将状态和值传给回调函数以便处理逻辑
}
render() {
return <div>
<Comp {...this.props} getFieldDec={this.getFieldDec} validateFields={this.validateFields} /> //挂载validateFields
</div>
}
}
}
export default Form
4.在Login中使用高阶函数来强化表单
//Login.jsx
class Login extends React.Component {
submit=(rets,values)=>{ //表单发送事件
console.log(rets,values)
}
render() {
const { getFieldDec, validateFields } = this.props //经过Form的强化我们已经在新组件上挂载了这两个方法
return <div className='login'>
<div className='card'>
<>
{
getFieldDec('phone', { rules: [{ required: true, message: '请输入手机号' }] })(<input type='text' />)
}//getFieldDec函数传入field,option返回一个新的函数,然后再执行这个返回的函数传入<input type='text' />得到一个强化后的新inpu组件
</>
<>
{
getFieldDec('password', { rules: [{ required: true, message: '请输入密码' }] })(<input type='text' />)
}
</>
<button onClick={() => validateFields(this.submit)}>登录</button>
</div>
</div>
}
}
export default Form(Login)//使用Form高阶组件传入Login组件进行强化返回一个新的组件
小结:
使用Form()传入一个Login组件,Form函数执行返回一个匿名class,这个匿名class上我们给他加了getFieldDec,validateField,validateFields方法,将这些方法挂载到了Login组件上,最后Login组件就有了验证表单,获取表单数据,强化input组件的方法,当我们使用getFieldDec方法,传入input的name和配置项,我们将这些拿到的配置项储存,它在返回一个新的函数,执行新的函数出入input组件,我们克隆这个组件为他加上必要的扩展name,value,change事件,并返回这个被强化的组件