0
点赞
收藏
分享

微信扫一扫

uni-app开发日志[2022022701]:解决因异步原因导致子组件调用父组件中uni-form表单验证事件时发生的错误及uniform、promise、async、await的同步异步使用注意点

蓝莲听雨 2022-02-27 阅读 76

标题不知道怎么取好,有建议留言

先对uni-form的部分表单验证有个了解 uni-forms表单其他方法说明

问题

一般情况下子组件是这样调用父组件事件的,比如我们写了一个发送短信验证码的组件,但是首先要通过父组件提供的验证规则后才能发送。

子组件sms-code

//子组件通过click事件触发执行send,send中首先执行sendValidate验证
<input @click="send" />
//props提供验证相关属性,属于事件类型
sendValidate:{type:Function}
//methods中执行发送
send(){
	console.log('第一步:开始(1)');
	//首先执行props提供的验证事件
	if(!this.sendValidate()){
		console.log('第五步:判断后操作(2)');
		//这里先不返回
		//return;
	}
	console.log('第六步:判断结束(3)');
	//执行发送
	uni.request({
		...
		console.log('第七步:发送验证码(4)');
	});
	...
	console.log('第八步:结束(5)');
}

父组件

//template中调用该组件
<sms-code :sendValidate="validate"></sms-code>
//methods中写入一个validate方法
validate(){
	console.log('第二步:验证开始(a)');
	let r = false;
	//uni-form针对单一控件的验证规则,这里验证用户名及手机
	this.$refs.form.validateField(['name', 'mobile']).then((res)=>{		
		console.log('第三步:验证中(b)');
		r = (!res)?false:true;
	});
	console.log('第四步:验证结束(c)');
	return r;
}

执行后会发现,顺序不对。

第一步:开始(1)
第二步:验证开始(a)
第四步:验证结束(c)
第五步:判断后操作(2)
第六步:判断结束(3)
第八步:结束(5)
第三步:验证中(b)
第七步:发送验证码(4

这样的话,没等判断成功就执行下去了。

分析

原因很简单,就是因为this.$refs.form.validateField()uni.request()为异步执行,所以执行顺序就被排到了后面。
本文不研究uni.request(),这里只是演示同步异步在一起后的顺序。

下面这二篇文章非常重要,帮助我真正理解并解决了问题。
Promise和Async/Await用法整理
vue 表单验证由异步变更为同步

好了,我写得太搞脑子了,也确实搞了我很久的脑子,还是看具体代码吧。

解决方法

现在将之前的代码进行改写:

子组件sms-code

//子组件通过click事件触发执行send,send中首先执行sendValidate验证
<input @click="send" />
//props提供验证相关属性,属于事件类型
sendValidate:{type:Function}
//methods中执行发送
async send(){
	console.log('第一步:开始(1)');
	//首先执行props提供的验证事件
	if(!await this.sendValidate()){
		console.log('第五步:判断后操作(2)');
		//这里先不返回
		//return;
	}
	console.log('第六步:判断结束(3)');
	//执行发送
	uni.request({
		...
		console.log('第七步:发送验证码(4)');
	});
	...
	console.log('第八步:结束(5)');
}

父组件

//template中调用该组件
<sms-code :sendValidate="validate"></sms-code>
//methods中写入一个validate方法
async validate(){
	console.log('第二步:验证开始(a)');
	let r = false;
	//uni-form针对单一控件的验证规则,这里验证用户名及手机
	await this.$refs.form.validateField(['name', 'mobile']).then((res)=>{		
		console.log('第三步:验证中(b)');
		r = (!res)?false:true;
	});
	console.log('第四步:验证结束(c)');
	return r;
}

这样执行顺序就对了,因为uni.request()依旧为异步,所以排到了最后。

第一步:开始(1)
第二步:验证开始(a)
第三步:验证中(b)
第四步:验证结束(c)
第五步:判断后操作(2)
第六步:判断结束(3)
第八步:结束(5)
第七步:发送验证码(4

深入挖掘

在解决这个问题时绕了很多弯路,这里写几个:

this.$refs.form.validateField()表单验证的三个部分

this.$refs.form.validateField(['name'],(res)=>{
	//res返回的是不符合验证规则的详细内容,如果验证成功则返回null,与then相反
}).then((res)=>{
	//res返回的是验证成功后该控件的值,如果验证失败则为null
}).catch((err)=>{
	//返回错误值
);

this.$refs.form.validateField()表单验证的catch()

系统会提示如下错误:

  • 警告uni-h5.es.js:13989 [Vue warn]: Unhandled error during execution of native event handler at <Button>
  • 错误Uncaught (in promise)

this.$refs.form.validateField()表单验证的then()可以分离

比如上面例子也可以这样写:

子组件sms-code

//子组件通过click事件触发执行send,send中首先执行sendValidate验证
<input @click="send" />
//props提供验证相关属性,属于事件类型
sendValidate:{type:Function}
//methods中执行发送
async v(){
	let r = false;
	await this.sendValidate().then((res)=>{
		r = (!res)?false:true;
	});
	return r;
},
async send(){
	if(!await this.v()){
		return;
	}
	//执行发送
	uni.request({
		...
	});
	...
}

父组件

//template中调用该组件
<sms-code :sendValidate="validate"></sms-code>
//methods中写入一个validate方法
validate(){
	return this.$refs.form.validateField(['name', 'mobile']);
}

本方法可以减少父组件的代码,之前代码需要在父组件或页面上标记asyncawait,各有用途:
如果子组件应用较广的话建议用之前的代码,让父组件中的函数必须提供布尔返回值,这样子组件容错率高。
如果子组件使用人群不是很懂代码,那么用这里的方法就很好了,因为他们不需要考虑同步异步的问题。

看见没?知道了原理,怎么拆怎么合就得心应手了。以后遇到其它同步异步问题时,可以加上promise()再来搞。

举报

相关推荐

0 条评论