表单时大家常用的,根据本站的百度统计后台显示来到道招网的程序很多都在关注《element-ui动态表单async-validate校验 please transfer a valid prop path to form item!》
看来很多网友对element-ui的校验(或者说是async-validator)使用不太熟悉,想了想还是有必要分享下element-ui的表单校验机制的。

首先表单校验分el-form, el-form-item以及里面的el-input, el-select等。
这里就以el-form, el-form-item和el-input组合为例。为了讲的更加详细,决定分一个系列来讲。毕竟码字多了就想草草结束。。。
先直接看el-form吧,这里的代码很少,毕竟主要内容是以slot插入的。

<template>
  <form class="el-form" :class="[
    labelPosition ? 'el-form--label-' + labelPosition : '',
    { 'el-form--inline': inline }
  ]">
    <slot></slot>
  </form>
</template>

属性就不多说了,跟校验相关的就是model和rules。还有就是validateOnRuleChange,它默认是true,并且有这样的watch存在

watch: {
    rules() {
        if (this.validateOnRuleChange) {
            this.validate(() => {});
        }
    }
},

默认规则改变会实时校验表单哦。

// 表单校验源码
validate(callback) {
    if (!this.model) {
        console.warn('[Element Warn][Form]model is required for validate to work!');
        return;
    }

    let promise;
    // if no callback, return promise
    if (typeof callback !== 'function' && window.Promise) {
        promise = new window.Promise((resolve, reject) => {
            callback = function(valid) {
                valid ? resolve(valid) : reject(valid);
            };
        });
    }

    let valid = true;
    let count = 0;
    // 如果需要验证的fields为空,调用验证时立刻返回callback
    if (this.fields.length === 0 && callback) {
        callback(true);
    }
    let invalidFields = {};
    this.fields.forEach(field => {
        field.validate('', (message, field) => {
            if (message) {
                valid = false;
            }
            invalidFields = objectAssign({}, invalidFields, field);
            if (typeof callback === 'function' && ++count === this.fields.length) {
                callback(valid, invalidFields);
            }
        });
    });

    if (promise) {
        return promise;
    }
},

官网的示例是这样的

methods: {
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            alert('submit!');
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    }

所以很多初学者是不是一直在用callback的方式啊,里面的参数为true时,才表示校验成功。这样是没错,但是如果你的项目是分多个表单,并且需要几个表单都校验通过才能提交,你是不是觉得不那么好写了。
其实官方已经给出了说明了

只是说就差给个demo了,毕竟部分初学者喜欢复制然后修改嘛。
我们根据上面的源码可以看出想使用校验,必须传递model属性。如果传递的callback不是方法的话,会定义一个promise,同时会定义callback为方法,参数依然是是否校验通过的结果。个人觉得这样还是很巧妙的,毕竟后面就可以完全按照传递了callback为前提继续写了,中途不用来回想如果用户是传递callback的模式呢还是直接使用promise的模式了,只是说最后发现如果有promise就返回即可。点个赞。
接着看this.fields,这是个数组,存储了哪些el-form-item是需要校验的。在created时进行存储的。
因为vue的父组件的created周期是在子组件的created之前的。

// el-form源码
created() {
    this.$on('el.form.addField', (field) => {
        if (field) {
            this.fields.push(field);
        }
    });
    /* istanbul ignore next */
    this.$on('el.form.removeField', (field) => {
        if (field.prop) {
            this.fields.splice(this.fields.indexOf(field), 1);
        }
    });
},

里面同时监听了移除校验某个el-form-item的事件。
到此el-form源码里面剩下的就不多了。只剩下以下三个方法了,放一起吧。

// el-form源码
        resetFields() {
            if (!this.model) {
                process.env.NODE_ENV !== 'production' &&
                    console.warn('[Element Warn][Form]model is required for resetFields to work.');
                return;
            }
            this.fields.forEach(field => {
                field.resetField();
            });
        },
        clearValidate(props = []) {
            const fields = props.length
            ? (typeof props === 'string'
               ? this.fields.filter(field => props === field.prop)
               : this.fields.filter(field => props.indexOf(field.prop) > -1)
              ) : this.fields;
            fields.forEach(field => {
                field.clearValidate();
            });
        },
        validateField(prop, cb) {
            let field = this.fields.filter(field => field.prop === prop)[0];
            if (!field) { throw new Error('must call validateField with valid prop string!'); }

            field.validate('', cb);
        }

分别是重置表单、清空校验、单独校验某个el-form-item
1. 重置表单:就是让里面每个item各自重置自己即可。
2. 清空校验:支持清空针对某个prop的校验,可以是字符串,也可以是数组。如果什么都不传的话,就去情况整个表单的校验了。
3. 单独校验某个item,根据传入的prop过滤出对应的field,如果有多个只取第一个,然后校验,执行回调。

需要说明下的是:
这里的field.validate需要在el-form-item里面看了。
el-form通过下面的方式实现了在它的子组件里面能够通过this.elForm来访问el-form的功能。Vue2.2.0+的功能

// el-form源码
provide() {
    return {
        elForm: this
    };
},

el-form的源码应该是讲的很清楚了,有需要的同学可以查看源码。

分类: Javascript

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据