Vue Element-ui表单校验规则实现

来自:互联网
时间:2021-07-09
阅读:
目录
1、前言
2、规则校验的入门模式
2.1、示例代码
2.2、form项
2.3、prop项
2.4、rules项
2.5、rule项
2.6、使用规则
2.7、规则校验的核心
3、规则校验的进阶模式
3.1、嵌套对象属性名
3.2、自定义校验器validator
3.3、类型type
3.3、数据转换transform
3.4、数值范围Range
3.5、枚举值
3.6、正则Pattern
3.7、长度len
3.8、空白whitespace
3.9、i18n
4、规则校验的高级模式
4.1、异步校验器asyncValidator
4.2、深层规则Deep rules
4.3、动态规则集
4.3.1、切换校验规则集
4.3.2、动态构建校验规则集
4.4、动态表格字段校验
4.5、多字段联合校验
5、参考文章

1、前言

  Element-ui表单校验规则,使得错误提示可以直接在form-item下面显示,无需弹出框,因此还是很好用的。

  我在做了登录页面的表单校验后,一度以为我已经很了解表单的校验规则。但我在深入使用表单校验规则时,遇到下列问题:

如何判断属性值是否在某个范围内,且这个范围可以任意指定? 如何判断属性值是否为某个值? 多个属性联合校验,当前属性的校验规则依赖于另一个属性的值,如何进行校验?如注册页面,ID类型有邮箱地址、手机号和身份证号码,选择不同类型,IDValue属性的校验规则是不同,如何处理? 两种模式,进入同一个表单组件,某些栏位可以不使用校验规则,即rules的对象会有所不同。这种情况如何处理?

  上述问题,让我感觉几乎成了小白。于是迫使我从头开始研究校验规则,查阅相关文档。

  本文分享一下对于表单校验规则的心得体会。

2、规则校验的入门模式

2.1、示例代码

  作为规则校验的入门,以登录页面为例,代码如下:

<template> 
  <div class="login-container">    
    <el-form ref="form" :model="form" :rules="rules" label-width="80px" class="login-form">
      <h2 class="login-title">XX管理系统登录</h2>
      <el-form-item label="用户名:" prop="username">
        <el-input v-model="form.username"></el-input>
      </el-form-item>
      <el-form-item label="密  码:" prop="password">
        <el-input v-model="form.password" type="password"></el-input>
      </el-form-item>
      <el-form-item label="验证码:" prop="verifyCode">
        <el-input v-model="form.verifyCode"></el-input>
        <div class="divVerifyCodeImg" @click="getVerifyCode(true)">
          <img id="verifyCodeImg" style="height:40px; width: 100px; cursor: pointer;" alt="点击更换" title="点击更换" />
        </div>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" id="login" style="width:160px" @click="submitForm('form')">登录</el-button>
      </el-form-item>
    </el-form>
  </div>  
</template>

<script>
import { mapMutations } from 'vuex'
export default {
  data() {
    return {
      form: {
        username: "",
        password: "",
        verifyCode: "",
      },
      rules: {
        username: [
          {required: true, message: "用户名不能为空", trigger: 'blur'},
        ],
        password: [
          {required: true, message: "密码不能为空", trigger: 'blur'},
          {min: 6, max: 30, message: "密码6-30位", trigger: 'blur'}
        ],
        verifyCode: [
          {required: true, message: "验证码不能为空", trigger: 'blur'},
        ]
      }      
    };   
  },
  methods: {
    // 提交登录
    submitForm(formName) { 
      let _this = this;     
      // 执行校验
      this.$refs[formName].validate(valid => {
        // 验证通过为true,有一个不通过就是false
        if (valid) {
          // 通过校验
          // 登录处理
          // ....
        } else {
          // 没通过校验
          console.log('验证失败');
          return false;
        }
      });
    },
  }  
}
</script>

2.2、form项

  form项,指明使用校验规则:

 <el-form ref="form" :model="form" :rules="rules" label-width="80px" class="login-form">

  :rules="rules" 指明了校验规则使用rules规则对象,你也可以使用其它名称,如rules1。

2.3、prop项

  prop项,指明哪些字段可能使用校验规则:

      <el-form-item label="用户名:" prop="username">
        <el-input v-model="form.username"></el-input>
      </el-form-item>

  如果prop项指定的属性值,如username,在rules中也有相应的项,则表示该属性值执行规则校验。这个属性必须是form的model属性绑定的数据对象的属性,本例中为form,其在data中定义:

      form: {
        username: "",
        password: "",
        verifyCode: "",
      },

2.4、rules项

  rules项,即校验规则集,其在data中定义,其名称必须与form的:rules属性绑定的rules规则对象名一致。

      rules: {
        username: [
          {required: true, message: "用户名不能为空", trigger: 'blur'},
        ],
        password: [
          {required: true, message: "密码不能为空", trigger: 'blur'},
          {min: 6, max: 30, message: "密码6-30位", trigger: 'blur'}
        ],
        verifyCode: [
          {required: true, message: "验证码不能为空", trigger: 'blur'},
        ]
      }      

  这是一个对象,每个元素的类型为:{属性名:[rule]},属性名对于prop的属性值。[rule]是一个规则数组,规则数组的每一项是一条对本属性的校验规则。

2.5、rule项

  rule项,即规则数组的元素,这是本文要重点探讨的项目。这里先就上述rules的各元素项解析一下:

required:表示是否必须有值,取值为true/false,如为true,表示必须有值,如果无值,则校验不通过;如为false,则允许无值,但在有值的情况下,不影响其它规则的使用。 message:提示消息,在校验不通过时提示此消息。 trigger:触发方式,取值为blur/change,blue表示失去焦点,一般在input组件中使用;change为值改变,一般在选择框中使用。 min:字符串最小长度。 max:字符串最大长度。

  有了这些解释,不难理解上述rules定义的各属性的校验规则。

2.6、使用规则

this.$refs[‘form'].validate(valid => {
        // 验证通过为true,有一个不通过就是false
        if (valid) {
          // 通过校验
        } else {
          // 没通过校验
        }
      });

  这个validate方法,要求所有校验规则都通过,才放行。其中,$refs[‘form'],指向form的ref属性值。

2.7、规则校验的核心

  规则校验的核心为为async-validator插件,官网:https://github.com/yiminghe/async-validator

  Element-UI使用了该插件,并进行了封装。官网:https://element.eleme.cn/#/zh-CN/component/form

  因此两边的资料都会有帮助。

3、规则校验的进阶模式

3.1、嵌套对象属性名

  有时候,prop不是一个简单的属性,而是包在其它对象下的属性。如:

      <el-form-item label="登 录 名:" prop="formData.loginName">
        <el-input v-model="form.formData.loginName" :disabled="form.formData.userId != 0"></el-input>
      </el-form-item>

  form的model绑定的form对象,其形式为:

        form:{
          // form数据字段,为提交后端方便,建议与UserInfo字段命名一致
          formData    : {
            userId      : 0,
            loginName   : '',
            passwd      : '',
            // ...
          },

          // 用户类型选择框当前显示值
          userTypeLabel : "",
          // ...
        },

  此时,rules的元素定义,不能用下列形式:

        formData.loginName: [
          {required: true, message: "登录名不能为空", trigger: 'blur'},
        ],

  这样,编译会报错!

  应使用下列形式:

    'formData.loginName': [
      {required: true, message: "登录名不能为空", trigger: 'blur'},
    ],

  即用单引号或双引号将之包起来,变成一个字符串。

3.2、自定义校验器validator

  关于自定义校验器validator,网上的相关资料很多,如常用正则检查的validator。

  规则定义方法:

          'formData.loginName': [
            {required: true, message: "登录名不能为空", trigger: 'blur'},
            {validator:loginNameValidator, trigger: 'blur'}
          ],

  表示'formData.loginName'属性使用了loginNameValidator的校验器。考虑到代码的复用,一般将自定义的校验器独成了js文件,便于其它页面或项目使用。

  在/src/common/目录下,创建validator.js文件,代码如下:

/* 登录名校验 */
export function loginNameValidator(rule, value, callback){
  const reg= /^[a-zA-Z][\w-. @]*$/;
  if(value == '' || value == undefined || value == null){
    callback();
  }else {  
    if (!reg.test(value)){
      callback(new Error('要求为:英文字母开头,后续为字母数字及_-. @符号'));
    }else {
      callback();
    }
  }
}

  在vue文件中导入此validator.js文件:

import {loginNameValidator} from '@/common/validator.js'

  如果需导入多个外部校验器,则在{}中包含多个,如{loginNameValidator,passwordValidator}。

  这里有个小坑,稍微提一句。

  根据目录结构,我先使用下列语句:

import {loginNameValidator} from '../../../common/validator.js'

  结果,编译错误,说找不到'../../../common/validator.js'文件,于是各种路径表示方法尝试,均告失败。最后还是使用改用@通过了,因为/bulid/webpack.base.conf.js中配置了alias,指示@表示src目录。

  回到自定义validator,其形式为:

function ValidatorFuncName(rule, value, callback)

  方法名,随意指定。

  实际上,其完整形式为:

function ValidatorFuncName(rule, value, callback, source, options)

  参数含义如下:

rule:指向规则的对象,可以在方法代码中,加入第一句:

console.log(rule);

可将rule参数打印出来看,就是本条规则的对象数据。

value:属性的值,该值为需要校验的值。

callback:指向校验结束的回调函数,如果校验通过,调用callback(),如果未通过,一般使用下列形式:

callback(new Error('具体的提示信息'));
  或带参数的提示:

return callback(new Error(`${rule.field} must be lowercase alphanumeric characters`));

  注意,字符串格式化,不是使用单引号括起来,而是用“~”符号括起来。

  也可以使用async-validator官网(https://github.com/yiminghe/async-validator)的方法:

util.format('%s must be lowercase alphanumeric characters', rule.field),

  util文件中包含format方法,这个util.ts文件,在官网的src/目录下,这是个ts文件,可以类似做一个公共方法。

  实际上,可以返回一个Error的数组,即errors,如:

      const errors = [];
      errors.push(new Error('要求为:英文字母开头,后续为字母数字及_-. @符号'));
      errors.push(new Error('3444要求为:英文'));
      return callback(errors);

  但从实际效果看,表单只显示了第一行的提示,估计Element的表单不支持显示多行错误信息。

source:为调用校验的属性对象,可以打印出来看一下。 options,附加参数,主要是预定义的消息格式,也可以打印出来看一下。

  更复杂的校验器,可以携带参数,如:

// 整数范围值校验
export const intRangeValidator = (min, max) => (rule, value, callback) => {
  var isInRange = (value >= min) && (value <= max);
  const reg = /^-?\d+$/;
  var isInt = reg.test(value);
  if (isInRange && isInt){
    return callback();
  }else{
    return callback(new Error(`要求是在${min}到${max}的整数 [${min}, ${max}]`));
  }
}

  使用方法:

      'formData.age': [
        {validator: intRangeValidator(1,100), trigger: 'blur'}
      ],  

  表示,formData.age属性的取值范围为1-100的整数。

  自定义校验器validator提供了自由发挥的空间,可以使用正则匹配、数值计算和比较等运算等,进行复杂的校验,因此比较常用。但用自定义校验器validator,有时会显得过于繁琐。

  自定义校验器validator不一定要放置在外部文件中,也可以放置vue文件中。

  放置在data中,但不被return所包括的位置,尾部没有逗号。

const loginNameValidator = (rule, value, callback) => {
  const reg= /^[a-zA-Z][\w-. @]*$/;
  if(value == '' || value == undefined || value == null){
    callback();
  }else {  
    if (!reg.test(value)){
      callback(new Error('要求为:英文字母开头,后续为字母数字及_-. @符号'));
    }else {
      callback();
    }
  }
}

  或直接在规则中定义:

          'formData.loginName': [
            {required: true, message: "登录名不能为空", trigger: 'blur'},
            {validator(rule, value, callback){
              const reg= /^[a-zA-Z][\w-. @]*$/;
              if(value == '' || value == undefined || value == null){
                callback();
              }else {  
                if (!reg.test(value)){
                  callback(new Error('要求为:英文字母开头,后续为字母数字及_-. @符号'));
                }else {
                  callback();
                }
              }                
            }, 
             trigger: 'blur'}
          ],

3.3、类型type

  类型type的基本用法如下:

      'formData.age': [
        {type: 'integer',message: "值要求为整数",trigger: 'blur'},
      ],

  类型也是一个规则项,如不符合类型要求,则提示错误信息。

  规则支持的类型如下:

string,字符串类型,这是默认类型。如不指定type,默认就是string。 number,数字类型。包括整数和小数。 integer,整数类型。 float,浮点数类型,此时不能为整数,必须有小数点。 boolean,布尔类型,true/false值。 array,数组类型。 object,对象类型,不能为数组。 enum,枚举类型,然后需要声明该枚举类型。 method,函数(或方法)类型。 regexp,正则类型,必须是一个合法的正则表达式,可以通过new RegExp来创建。 date,日期类型,值必须可以转为有效日期值。 url,url类型,值需要符合url格式。 email,email类型,符合邮箱格式格式。 hex,16进制表示的形式。如0xFF12。 any,任意类型,不限制。

  这里的url和email类型,可以直接用于相关含义的属性校验,如:

          'formData.email': [
            {type: 'email', message: "必须符合邮箱地址格式",trigger: 'blur'}
          ],  

  日期类型也比较有用,这些内置类型,使得我们可以不必通过自定义校验器validator来处理。

  对于数值类型(number,integer,float)以及boolean型,由于input输入的都为字符串,因此必须进行类型转换,否则校验通不过。这里涉及到transform的用法。

3.3、数据转换transform

  transform是一个钩子函数,在开始验证之前可以对数据先处理后验证。如下面示例:

      'formData.age': [
        {
            type: 'integer',
            message: "值要求为整数",
            trigger: 'blur',
            transform(value){return parseInt(value);},
        },
      ],

  经过transform类型转化后,formData.age属性的校验规则就能正常使用了,否则总是通不过类型校验。(这里实际上有点问题,如允许输出12ab这种形式的值,parseInt得到值为12)

  对于类型转换,transform还有更简洁而严格的表述:

  'formData.age': [
    {
        type:'integer',
        message: "值要求为整数",
        trigger: 'blur',
        transform:Number},
    },
  ],

  表示转换为数字类型,这样就行了。值为1.2或12ab都不能通过校验。

  transform除了类型转换外,还可以进行其它处理,如:

          'formData.age': [
            {type : 'string',pattern:/1/,message: "值要求为1-100的数",transform(value){return parseInt(value)>=1 && parseInt(value)<=100 ? "1" : "0";},}
          ],  

  等于某个值:

          'formData.age': [
            {type : 'string',pattern:/1/,message: "值要求必须为50",transform(value){return value == "50" ? "1" : "0";},}
          ],  

  不等于某个值:

      'formData.age': [
        {type : 'string',pattern:/0/,message: "值要求不能为50",transform(value){return value == "50" ? "1" : "0";},}
      ],  

3.4、数值范围Range

  Range不是规则的属性字段,其通过min和max属性来体现。

  如果类型type为string或array,则min和max表示长度。

  如果类型type为数值类型(number,integer,float),则min和max表示值的范围。如:

  'formData.age': [
    {
        type:'integer',
        message: "值要求为1-100的整数",
        min: 1,
        max:100,
        trigger:'blur',
        transform:Number,
    },
  ],

  这样,范围校验直接可使用规则的内置属性,在规则中进行描述,也无需用intRangeValidator校验器和正则匹配方式了。

3.5、枚举值

  枚举值类型的用法示例:

          'formData.idType': [
            {
                type: 'enum', enum: [2,4,6], message: `结果不存在`, trigger: ['change', 'blur'], transform(value) {return Number(value) * 2},
            },
          ],  
  或:

      'formData.gender': [
        {
            type: 'enum', enum: ['male','female'], message: `结果不存在`, trigger: ['change', 'blur'],
        },
      ],  

  使用有下列问题:

反应比较迟钝,就是一开始几次输入,没有校验,一旦有校验了,后面都就可以了。 对于后一种情况,即范围为字符串的集合,校验正常。对于前一种情况,即范围为整数型的,0也通过校验了,导致任意字符串也通过校验了,这是一个bug。

  因此,也可以利用字符串枚举值,来校验范围:

          'formData.age': [
            {
                type : 'enum',
                enum:["1"],
                message: "值要求为1-100的数",
                transform(value){
                    if (!isNaN(value)){
                      return parseInt(value)>=1 && parseInt(value)<=100 ? "1" : "0";
                    }else{
                      return "0";
                    }
               }
            },
          ],  

  注意:此时1e3,9e811被认为是通过校验了,因为parseInt函数只取e前面的数字,而isNaN认为是数字。看来还是需要与正则规则配合才行。

3.6、正则Pattern

  pattern属性,就是正则表达式匹配校验规则,如:

          'formData.loginName': [
            {required: true, message: "登录名不能为空", trigger: 'blur'},
            {pattern:/^[a-zA-Z][\w-. @]*$/,
             message:'要求为:英文字母开头,后续为字母数字及_-. @符号',
             trigger: 'blur'}
          ],

  效果与之前的loginNameValidator校验器相同,区别在于loginNameValidator可以复用,保持一个正则校验,如需修改,只需改动一处。而使用pattern则不然。但使用pattern可以少写自定义校验器,给了用户一个选择。

  使用pattern属性,可以进行等于某个值某个值的校验。

  等于某个值:

{pattern:/120/,message:'必须必须为120',trigger: 'blur'}

  关于js正则表达式,可先用js正则表达式在线测试工具测试一下,检查是否达到预期效果。js正则表达式在线测试地址:https://c.runoob.com/front-end/854

3.7、长度len

  len属性,如果类型为string或array,则冷表示长度。如果为数字型,则表示数字值就是len属性值。

  len属性与min、max属性同时出现了,len属性有更高的优先级。

  len属性,可用于格式化的字符串校验,如身份证号码长度。

  len也可用于等于某个数值的校验,如:

  'formData.age': [
    {
        type:'integer',
        message: "值要求必须为6周岁",
        len: 6,
        trigger:'blur',
        transform:Number,
    },
  ],

3.8、空白whitespace

  空白表示全部由空格组成的字符串,规则的类型必须为string。如果匹配规则,则告警提示。如:

          'formData.email': [
             {whitespace: true, message: '只存在空格', trigger: 'blur'}
          ], 

  值为空格,会提示告警。

  如果不希望空格干扰校验,可用transform来处理:

transform(value) { return value.trim();}

3.9、i18n

  message支持i18n,即国际化处理,如集成vue-i18n,message属性的用法如下:

message: () => this.$t( 'about' ) 

  中文语言显示“关于”,英文语言显示“about”。

  当然,你也可以换成任意的其它函数,如:

message: () => this.myMessageHandler(MessageId,paramValues)

4、规则校验的高级模式

4.1、异步校验器asyncValidator

  异步校验器用于远程访问,利用ajax或axios请求数据,对响应数据进行校验或对异常进行提示。

  本地页面校验,属于串行校验,逐个检查各字段的校验规则,遇到未通过即返回校验失败。

  远程校验,为异步校验,多个请求,响应时间各有不同,响应的先后次序就无法预知。

  异步校验的作用:可以将前端和后端针对相同属性字段,使用相同的校验规则,统一由后端提供校验。但这同样增加了前后端沟通和一致性维护的成本。

  目前暂时未用到异步校验器,这里用官网的示例:

asyncField1:{asyncValidator: myAsyncValidator}
  myAsyncValidator可类似validator位置放置。假设放置在data中。

const myAsyncValidator = (rule, value, callback) => {
      ajax({
        url: 'xx',
        value: value,
      }).then(function(data) {
        callback();
      }, function(error) {
        callback(new Error(error));
      });
    }

  Promise异步字段校验:

 const myAsyncValidator = (rule, value) => {
      return ajax({
        url: 'xx',
        value: value,
      });
    }

  区别在于Promise异步字段校验,需要使用者自己写上.then/.catch处理逻辑,不支持回调。

  异步校验,还涉及到Options属性,

options: { first: true },

  first为true,表示多个异步校验遇到第一校验失败就不再处理其它异步校验。

4.2、深层规则Deep rules

  对于对象Object或数组Array的校验,需要具体到每一个元素(成员),这里就要用到Deep rules。

  Deep rules涉及到fields和defaultField两个属性。

  如官网示例(按照习惯形式略作修改):

  对象的深层校验:

rules : {
  address: [{
    type: 'object',
    required: true,
    options: { first: true },
    fields: {
      street: [{ type: 'string', required: true }],
      city: [{ type: 'string', required: true }],
      zip: [{ type: 'string', required: true, len: 8, message: 'invalid zip' }],
    },
  }],
  name: [{ type: 'string', required: true }],
};

  数组的深层校验:

rules : {
  roles: [{
    type: 'array',
    required: true,
    len: 3,
    fields: {
      0: [{ type: 'string', required: true }],
      1: [{ type: 'string', required: true }],
      2: [{ type: 'string', required: true }],
    },
  }],
};

  数组的深层校验,看起来比较傻,每个成员都要设置校验规则,对于动态数组,似乎也不知该如何设置。

  defaultField属性,使我们对字段校验规则有了统一设置的手段。此属性可以作用在校验属性字段上,也可以作用在fields上。

  例如:

rules : {
  urls: [{
    type: 'array',
    required: true,
    defaultField: { type: 'url' },
  }],
};

  如果是对象数组,该如何设置?可如下方式:

rules : {
  persons: [{
    type: 'array',
    required: true,
    defaultField:{
        type: 'object',
        required: true,
        fields: {
            address: [{
                type: 'object',
                required: true,
                fields: {
                    street: [{ type: 'string', required: true }],
                    city: [{ type: 'string', required: true }],
                    zip: [{ type: 'string', required: true, len: 8, 
                           message: 'invalid zip' }],
                },
            }],
            name: [{ type: 'string', required: true }],                  
        }
    }
  }],
};

  数组套对象,对象套子对象,看起来有点复杂。

4.3、动态规则集

  有时候不同模式进入表单,需要应用不同的规则。如新增和编辑操作,显示同一个页面组件。但此时对页面需要校验的属性字段有所不同,如何设置?

  有两个处理方案。方案1是配置两套规则集,根据不同模式进行切换;方案2是配置总的规则集,根据不同模式抽取合适的属性字段和规则,动态构建规则集。

4.3.1、切换校验规则集

  切换校验规则集,示例代码如下:

      // data 部分
      // 当前规则集
      rules:{},
      // 模式1规则集
      rules1:{
         ...
      },
      // 模式2规则集
      rules2:{
          ...
      },

      // methods部分
      // 动态切换
      // 页面初始化
      init(obj,data){
        this.prevForm = obj;

        // 设置页面可见
        this.visible = true;

        // DOM更新之后执行
        this.$nextTick(()=>{
          // 重置当前页面的所有字段值
          this.$refs['form'].resetFields();

          if (data){
            // 模式1
            this.form.patternType = 1;        
          }else{
            // 模式2
            this.form.patternType = 2;
          }        
          // 设置校验规则
          this.setValidRules(this.form.patternType);
        }
    },
      setValidRules(patternType){
        if(patternType == 1){
            this.rules = this.rules1;
        }else if(patternType == 2){
            this.rules = this.rules2;
        }
      },

  这样,根据不同模式,切换了校验规则集。为了切换规则时,立即执行规则校验,需要设置el-form的validate-on-rule-change为false,即:

<el-form ref="form" :model="form" :rules="rules" 
         :validate-on-rule-change=false 
         class="useredit" label-width="100px" style="line-height: 30px;">

4.3.2、动态构建校验规则集

  动态构建校验规则集,示例代码如下:

      // data 部分
      // 当前规则集
      rules:{},
      // 规则全集
      allRules:{
          'formData.loginName': [
            {required: true, message: "登录名不能为空", trigger: 'blur'},
            {validator:loginNameValidator, trigger: 'blur'}
          ],
          'formData.passwd': [
            {required: true, message: "密码不能为空", trigger: 'blur'},
            {min: 6, max: 18, message: "密码6-18位", trigger: 'blur'}
          ],
          'formData.email': [
             {type: 'email', message: '需要符合email格式', trigger: 'blur'}
          ],          
          genderLabel: [
            {required: true, message: "性别不能为空", trigger: 'change'},
          ],
          userTypeLabel : [
            {required: true, message: "用户类型不能为空", trigger: 'change'},
          ],
          deptLabel: [
            {required: true, message: "部门不能为空", trigger: 'change'},
          ]
      },
          
      // methods部分
      // 动态切换
      // 页面初始化
      init(obj,data){
        this.prevForm = obj;

        // 设置页面可见
        this.visible = true;

        // DOM更新之后执行
        this.$nextTick(()=>{
          // 重置当前页面的所有字段值
          this.$refs['form'].resetFields();

          if (data){
            // 模式1
            this.form.patternType = 1;        
          }else{
            // 模式2
            this.form.patternType = 2;
          }        
          // 设置校验规则
          this.setValidRules(this.form.patternType);
        }
    },
      setValidRules(patternType){
        if (patternType == 1){
          // 模式1
          // 先清空,再设置          
          this.rules = {};
          this.rules['genderLabel'] = this.allRules['genderLabel'];
          this.rules['userTypeLabel'] = this.allRules['userTypeLabel'];
          this.rules['deptLabel'] = this.allRules['deptLabel'];
          this.rules['formData.email'] = this.allRules['formData.email'];
        } else{
          // 模式2,需要验证登录名和密码
          this.rules = {};
          this.rules['formData.loginName'] = this.allRules['formData.loginName'];
          this.rules['formData.passwd'] = this.allRules['formData.passwd'];
          this.rules['genderLabel'] = this.allRules['genderLabel'];
          this.rules['userTypeLabel'] = this.allRules['userTypeLabel'];
          this.rules['deptLabel'] = this.allRules['deptLabel'];
          this.rules['formData.email'] = this.allRules['formData.email'];
        }
      },          

  同样也需要设置el-form的validate-on-rule-change为false。

4.4、动态表格字段校验

  有的表单,使用了可编辑的动态表格,如添加一数据行,直接在数据行中输入数据,然后提交。此时需要对数据行各字段的输入进行校验。

  有2个方案。

  方案1使用Deep rules的defaultField,对对象数组进行字段校验,见上面的示例代码。

  方案2,在el-form-item层级使用rules属性绑定该字段规则。

4.5、多字段联合校验

  多字段联合校验应用场合还是比较常见的,如文本开始的问题,不同ID类型,有不同的校验规则;如密码验证,两次密码要相同;如购买数量不能超过库存数量,时间段开始时间要不大于结束时间,等等。

  关键技巧,利用校验器的第一个参数rule,添加一个或若干个自定义属性,传递信息到校验器进行处理。使用方法如下:

  作为示例,假设'formData.email'字段校验依赖于userType的值。

          'formData.email': [            
             {validator : idFieldWithTypeValidator, trigger: 'blur',}
          ],

  没有办法初始绑定:

          'formData.email': [            
             {validator : idFieldWithTypeValidator, trigger: 'blur','userType':this.form.formData.userype}
          ],

  这样写,浏览器调试器显示错误,提示调用resetFields出错。

  因此,正确的形式为:

      'formData.email': [            
         {validator : idFieldWithTypeValidator, trigger: 'blur',}
      ],

  或:

      'formData.email': [            
         {validator : idFieldWithTypeValidator, trigger: 'blur','userType':0}
      ],

  然后,在页面初始化时,或选择框选择改变的chage事件方法中,动态设置规则中userType属性的值:

this.rules['formData.email'][0]['userType'] = this.form.formData.userType;

  试验结果,用$set没法动态绑定,即下列语句没有作用:

this.$set(this.allRules['formData.email'][0],'userType',this.form.formData.userType);

  好了,现在可以编写一个联合校验器idFieldWithTypeValidator了。简单起见,在data部分编写:

      const idFieldWithTypeValidator = (rule, value, callback) =>{
        // 获取用户类型
        console.log(rule);
        return callback();
      }

  测试一下,在浏览器控制台输出rule的打印信息如下:

{
    "userType": 2,
    "field": "formData.email",
    "fullField": "formData.email",
    "type": "string"
}

  此时,userType已经通过rule参数传入,现在可以进行联合校验了。

  import {loginNameValidator,phoneNoValidator,idNoValidator,eMailValidator} from '@/common/validator.js'
  export default {
    data() {
      // 不同类型情况下的ID字段校验器
      const idFieldWithTypeValidator = (rule, value, callback) =>{
        // 获取用户类型
        console.log(rule);
        if (rule.userType == 1){
          // 手机号码
          phoneNoValidator(rule, value, callback);
        }else if(rule.userType == 2){
          // 身份证号码
          idNoValidator(rule, value, callback);
        }else if(rule.userType == 3){
          // email
          eMailValidator(rule, value, callback);
        }
      }

      return {
          ....
      }            
    },
    ...
  }

其中phoneNoValidator、idNoValidator、eMailValidator分别是手机号码校验器、身份证号码校验器、邮箱格式校验器,由validator.js中输出,idFieldWithTypeValidator校验器根据userType参数的取值不同,分别调用了相关的validator类型的校验器。当然,在idFieldWithTypeValidator的方法代码中,也可以将各个校验器的代码搬过来,不调用外部校验器。

5、参考文章

除了官网资料外,本文还参考了下列文章:

[1]、浅析async-validator源码,https://zhuanlan.zhihu.com/p/32306570?edition=yidianzixun&utm_source=yidianzixun&yidian_docid=0I5IikUl

[2]、Vue中Element表单验证的基本要素, https://www.php.cn/js-tutorial-406545.html

[3]、element-ui 表单校验 Rules 配置,https://www.cnblogs.com/loveyt/archive/2020/07/11/13282518.html

[4]、Element Ui使用技巧——Form表单的校验规则rules详细说明,https://www.cnblogs.com/xyyt/p/13366812.html

返回顶部
顶部