最近看了很多高阶组件的资料和视频,学到了一些东西,写个input校验框复习一下。
//我们来创建两个组件,名字随意,一个高阶组件一个展示组件,为了能够使用装饰器展示组件我们使用类组件
//创建展示组件InputComp
class InputComp extends React.Component {
onsubmit = () => {
}
render(){
return (
<div>
<div>
用户名:<input />
</div>
<div>
密码:<input type="password"/>
</div>
<button onClick={this.onsubmit}>提交</button>
</div>
)
}
}
然后我们创建高阶组件,我们希望高阶组件可以完成对所有表单的验证,并且将验证的结果和最终提交的值都返回给我们,以便于我们根据结果和value做下一步的操作,比如注册、登录等操作。
我们通过高阶组件给展示组件传递一个方法:gradeInput,该方法接收两个参数,一个name值比如:uname,password,phone等,另一个参数是验证内容的数组对象我们可以模仿ant-design放到rules中。这个方法返回一个被我们处理过的input。
//创建高阶组件
function CheckInput(Comp){
return class extends React.Component{
constructor(props){
super(props);
this.obj = {};//定义一个空对象存放验证信息
this.state = {};//定一个状态保存input值和输入有误时的提示信息
}
gradeInput = (name, option) => {
this.obj[name] = option;//将传过来的对象通过计算属性存入obj
return Iptcomp => {//gradeInput函数返回一个带参数的函数,我们将<input />输入框作为参数传入,来为他添加属性和方法
return (
<div>
{
// 由React.createElement生成的元素不能直接修改,我们需要克隆一份
React.cloneElement(Iptcomp, {
name: name, //给input添加name属性并将传入的name赋给他
value: this.state[name] || "", // 添加value属性,我们会通过下面的onChange方法将输入的值通过计算属性存到状态中,如果计算属性还不存在则赋予空值,不给默认空值会报警告信息
onChange: this.handleChange //为input添加方法
})
}
{//如果有提示信息,一样通过计算属性存到状态,如果有的话就展示
this.state[name + 'msg'] && <p style={{color: "red"}}>{this.state[name + 'msg']}</p>
}
</div>
)
}
}
handleChange = (e) => {//实现onChange方法我们先打印一下
this.setState({[e.target.name]: value});//将value存入state中
console.log(e.target.value,e.target.name)
}
render(){
return(//将gradeInput方法传给要修饰的组件
<Comp {...this.props} gradeInput={this.gradeInput} ></Comp>
)
}
}
}
接着我们修改一下InputComp,并用装饰器装饰
@CheckInput
class InputComp extends React.Component {
onsubmit = () => {
}
render(){
const { gradeInput } = this.props;
return (
<div>
<div>
用户名:{
gradeInput("uname",{
rules:[{required: true, message: "用户名不能为空"}, {type: "password", reg: /^[a-zA-Z]/, message: "用户名必须以字母开头"}]
})(<input />)
}
</div>
<div>
密码:{
gradeInput("pwd",{
rules:[{required: true, message: "密码不能为空"}]
})(<input type="password"/>)
}
</div>
<button onClick={this.onsubmit}>提交</button>
</div>
)
}
}
export default InputComp
启动项目查看控制台有没有输出name和value
1.png证明我们写的的代码没问题,下面接着完善开始写校验的部分,校验分两块一个是每个input的校验,一个是提交的校验。
//先修改高阶组件
function CheckInput(Comp){
return class extends React.Component{
constructor(props){
super(props);
this.obj = {};
this.state = {};
}
verificateFiled = (name) => {//校验输入框,在handleChange里面调用
//我们之前把校验信息存入obj的计算属性中,通过遍历去挨个校验
const isverif = this.obj[name].rules.map(item => {
if(item.required){//校验必填项
if(this.state[name]){
this.setState({[name + "msg"]: ""});//校验成功清空提示信息并返回true否则返回false
return true
}
this.setState({[name + "msg"]: item.message})
return false
}
if(item.reg && this.state[name]){//如果我们有传入正则,则进行正则校验
if(item.reg.test(this.state[name])){
this.setState({[name + "msg"]: ""})
return true
}
this.setState({[name + "msg"]: item.message})
return false
}
})
//遍历完会返回一个true和false的数组isverif,只要有一个为false则为不通过
return isverif.indexOf(false) > -1 ? false : true;
}
verificateAll = (callback) => {//校验所有input,主要是为了提交时验证,所以我们需要把这个函数传递给展示组件,并给他传入一个函数,方便提交的后续操作
const ispass = Object.keys(this.obj).map(item => {//取出obj中的key值,当时存储的时候是以传入的name作为key的,将key传给verificateFiled
return this.verificateFiled(item);
})
//返回的ispass也是一个true和false组成的数组,只要存在false即为校验不通过
//我们将最终的校验结果,并把state状态中的值传入,便于我们后续提交
callback(!ispass.includes(false), this.state);
}
handleChange = (e) => {
const {name, value} = e.target;
//值改变时就开始校验,因为状态的异步更新机制,我们要在setState的回调函数中调用,保障每次拿到的是最新的值
this.setState({[name]: value}, () => this.verificateFiled(name));
}
gradeInput = (name, option) => {
this.obj[name] = option;
return Iptcomp => {
return (
<div>
{
React.cloneElement(Iptcomp, {
name: name,
value: this.state[name] || "",
onChange: this.handleChange
})
}
{
this.state[name + 'msg'] && <p style={{color: "red"}}>{this.state[name + 'msg']}</p>
}
</div>
)
}
}
render(){
return(//将verificateAll也传给展示组件
<Comp {...this.props} gradeInput={this.gradeInput} verificateAll={this.verificateAll}></Comp>
)
}
}
}
给展示组件添加提交方法
@CheckInput
class InputComp extends React.Component {
//提交方法
onsubmit = () => {
this.props.verificateAll((isverify, allVal) => {//我们在高阶组件中为verificateAll的回调函数传入了校验是否成功和state中保存的值
if(isverify){
console.log("校验成功", allVal)
}else{
console.log("请检查输入的内容")
}
})
}
render(){
const { gradeInput, onsubmit } = this.props;
return (
<div>
<div>
用户名:{
gradeInput("uname",{
rules:[{required: true, message: "用户名不能为空"}, {type: "password", reg: /^[a-zA-Z]/, message: "用户名必须以字母开头"}]
})(<input />)
}
</div>
<div>
密码:{
gradeInput("pwd",{
rules:[{required: true, message: "密码不能为空"}]
})(<input type="password"/>)
}
</div>
<button onClick={this.onsubmit}>提交</button>
</div>
)
}
}
export default InputComp
这样便实现了input校验的封装,我们下来检测一下是否可以正常校验。
2.png
可以看到,当我们输入不符合要求时,校验信息是正确的,点击提交控制台也有正确的提示。
下来,我们正确输入后点击按钮看是否正常输出input的值
3.png
网友评论