携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
场景
我们用表单提交的时候都会有校验的,最基本的就是element-ui自带的表单校验,就是那个红字提醒,就像这样的
(element-ui 基本表单校验)
但是我们有时候要的不是表单里面某个表单项目的校验,例如现在我想要校验的是如果活动名称超过5个字并且活动区域小于2个字加上活动时间在当年的2月份里面的时候就提示用户,【你确定要提交这个表单吗?】这种联合条件的校验,这种我们往往就会使用到element里面的MessageBox这个组件来做提示,因为这个是需要用户去做选择的,就像下面这个
(MessageBox组件)
当用户点击【取消】就不予提交,点击【确定】就提交,这种相信大家也都用过很多次,我这次在做一个表单提交的时候这种校验实在是,太太太太多了,一共好像20几个吧(我的场景里面是一个线性的提示,就是没有要根据确定/取消再必须要去调另外的校验)按照提供最常规写法写一个:
(messagebox使用代码)
那我的就是类似这种(只是举例一下,真的写完超级无敌长),好可怕的回调地狱:
(messagebox回调地狱)
看看我的场景里面的真实逻辑,基本是这样的:
开始解决
既然我们已经了解了这一个线性的提示,就是一条线下来,并没有那种分岔的校验,那么我们就来写吧,刚刚说到一个很恐怖的东西回调地狱,那我们就用async await方法来避免回调地狱就好啦,我们先简单封装一下MessageBox这个组件的先,每次都写一堆参数挺麻烦:
封装一下MessageBox
import {MessageBox} from "element-ui";
// 这是【确定】【取消】弹框
export function isConfirm(message, title = '提示') {
return MessageBox({
title,
message,
showClose: false,
showCancelButton: true,
})
}
// 这是【确定】弹框
export function justConfirm(message, title = '提示',) {
return MessageBox({
title,
message,
showClose: false,
showCancelButton: false,
})
}
使用async awit写个check方法
必备小知识:这个messagebox的返回是:
- 确定:返回字符串'confirm'
- 取消:返回字符串'cancel'
- 关闭:返回字符串'close' (这个我没用到,我的场景取消了关闭操作)
// 基本就是这样
async function check() {
if (/**逻辑代码,触发1*/) {
// 这里回返回两个参数
// 如果是确定的话会返回字符串 'confirm'
// 如果是取消回触发到catch,就会返回字符串 'cancel'
const result = await isConfirm('提示语').catch(error => error);
if (result === 'cancel') {
return false;
}
}
if (/**逻辑代码,触发2*/) {
const result = await isConfirm('提示语').catch(error => error);
if (result === 'cancel') {
return false;
}
}
}
// 实际上那个触发的逻辑比较复杂,一般要写成单个的方法
function judgeOne() { /** 逻辑判断,返回一个布尔值 */ }
function judgeTwo() { /** 逻辑判断,返回一个布尔值 */ }
// 所以最后出来就是这样
async function check() {
if (judgeOne()) {
const result = await isConfirm('提示语').catch(error => error);
if (result === 'cancel') {
return false;
}
}
if (judgeTwo()) {
const result = await isConfirm('提示语').catch(error => error);
if (result === 'cancel') {
return false;
}
}
}
再封装一下check方法
上面已经把回调地狱解决了,但是整个方法看起来非常的长,因为我说了有20个判断,那怎么做我们把每个提示的:
- 提示判断(也就是要不要进入这个校验,方法要给回一个布尔值)
- 提示语(就是你要弹框展示给用户的东西)
- 弹框(是需要只有【确定】按钮的弹框还是【确定】【取消】都要有的)
- 反馈按钮的动作(点击了【确定】【取消】,是继续往下走,还是终止)
都放到单独方法去判断,里面去就是你的方法要返回一个对象,里面应该有这些:
{ isCheck: true, message: '提示语', type: isConfirm, confirmIsContinue: true }
- isCheck:如果true就是进入校验,false就是忽略这个校验
- message:就是提示语
- type: 弹框类型,我这里写的时候直接引入了方法,使用的时候会直接调用
- confirmIsContinue:如果true则代表确定是继续,取消是终止;反之就相反确定是终止,取消是终止
然后我们接着我们的校验函数是需要循环调用不同的方法,我们把方法都装进一个方法数组[check1, check2],然后只要循环完成了这个方法数组,那我们校验就算成功了,如果某个方法中断了,那么就是返回false,大概就是这个思路了,让我们看代码吧:
单独方法去判断
// 这里引入了封装过的提示
import {isConfirm, justConfirm} from "./remind";
testName() {
if (this.name === 'jo') {
// 如果是不需要进入校验的,返回的对象只需要有isCheck,毕竟不进入校验就不需要做任何东西了
return { isCheck: false, }
} else {
// 这个type,你可以写一个值,然后被调用时候再去判断调什么提示弹框,我这里是引入了,就直接写方法了
return { isCheck: true, message: 'must get joe!', type: justConfirm, confirmIsContinue: true }
}
},
testAge() {
if (this.age > 20) {
return { isCheck: true, message: 'click cancel will continue', type: isConfirm, confirmIsContinue: false}
} else {
return { isCheck: false }
}
}
数组循环调用校验
async check() {
// 这里数组装的就是每个的校验方法
const checkMethod = [this.testName, this.testAge]
// 然后我们这里开始循环
for (let method of checkMethod) {
// 解构赋值拿到调用校验方法返回的值
const { isCheck, message, type: remind, confirmIsContinue } = method();
// 如果是符合调用校验条件则继续,否则就下一个循环
if (isCheck) {
// 我们这里拿到字符串,用户点击的是confirm还是cancel
const confirmOrCancel = await remind(message).catch(error => error);
// 然后通过【反馈按钮动作】配合【用户点击返回的值】
// 判断是继续还是终止
const result = confirmIsContinue ? confirmOrCancel === 'confirm' : confirmOrCancel === 'cancel'
// 如果是false则终止,否则继续循环
if (!result) return false;
}
}
// 循环结束
// 通过所有方法校验,可以提交表单
return true;
}
如果你的单个校验方法里面是需要调后端的接口,就是也是异步的,那你也要相应的加上async,和awit:
async testName() {}
async check() { ...省略 const {...省略} = await method() }
你的校验更复杂?
刚刚也说了,我们的20个校验是线性下来的,并没有那种分岔的,也就是这种:
这个我的需求倒是没有,但是我也想了一下,大致的思路也是把那个装在校验函数的数组更改一下,换成对象数组,里面有属性说明后面跟的是哪个函数,就是如果确定调用哪个函数,取消调用哪个:
const checkMethod = [{
main: judgeMethod,
confirm: judgeTwoMethod,
cancel: judgeThreeethod
}, {
main: judgeTwoMethod
}, {
main: judgeTwoMethod
}]
循环时候就需要判断是不是需要根据本次判断的【确定】【取消】去确定下一个调用的判断函数,需要的话就循环找到,大概就是这么个思路,我就不写了,都大同小异!!
好了,要去加班了!!!