element提醒弹框(一个提交很多校验弹框)

352 阅读6分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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个判断,那怎么做我们把每个提示的:

  1. 提示判断(也就是要不要进入这个校验,方法要给回一个布尔值)
  2. 提示语(就是你要弹框展示给用户的东西)
  3. 弹框(是需要只有【确定】按钮的弹框还是【确定】【取消】都要有的)
  4. 反馈按钮的动作(点击了【确定】【取消】,是继续往下走,还是终止)

都放到单独方法去判断,里面去就是你的方法要返回一个对象,里面应该有这些:

{ isCheck: true, message: '提示语', type: isConfirm, confirmIsContinue: true }

  1. isCheck:如果true就是进入校验,false就是忽略这个校验
  2. message:就是提示语
  3. type: 弹框类型,我这里写的时候直接引入了方法,使用的时候会直接调用
  4. 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
}]

循环时候就需要判断是不是需要根据本次判断的【确定】【取消】去确定下一个调用的判断函数,需要的话就循环找到,大概就是这么个思路,我就不写了,都大同小异!!

好了,要去加班了!!!