道招

element-ui表单源码解析之el-form

如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

element-ui表单源码解析之el-form

表单时大家常用的,根据本站的百度统计后台显示来到道招网的程序很多都在关注《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的源码应该是讲的很清楚了,有需要的同学可以查看源码。

更新时间:
上一篇:Vue2.6.10源码分析(一)vue项目怎么神奇的跑起来的下一篇:element-ui表单源码解析之el-form-item

相关文章

element-ui表单源码解析之el-form-item

上一篇看了el-form,功能比较简单,现在来看看el-form-item &lt;!--el-form-item源码--&gt; &lt;template&gt; &lt;div cla 阅读更多…

element-ui表单源码解析之el-input

关于表单校验el-input做的主要工作就是跟el-form-item交互,把input的相关事件发送给el-form-item,上一篇已经讲到在el-form-item的mounted的生命周期里 阅读更多…

element-ui合并单元格使用详解

最近做的一个叫组合商品的项目,里面需要用到饿了么的合并单元格。 看了看官方的示例,发现所谓的单元格跟我之前的认知不一样,比如有两个组合A、B,其中A是由a1和a2组合在一起(即A = [a1, 阅读更多…

el-table搭配el-form实现数据校验

之前已经讲过一个关于el-form的校验的文章《 element-ui动态表单async-validate校验 please transfer a valid prop path to form i 阅读更多…

命令式组件Message、Dialog的主流写法分析

这里还是以element-ui为例,那我们就看看里面的Message。 它的dom结构什么的就写在node-modules/element-ui/packages/notification/src/ 阅读更多…

wangEditor输入中文后直接粘贴bug来了解compositionstart

昨天有人反馈邮件编辑过程中的一个报障,具体内容就是在编辑器中输入中文然后直接粘贴先前复制好的信息,然后出现了bug,比如之前复制了订单号“1234”,再输入“您的订单号”后直接粘贴,编辑器内显示的结 阅读更多…

关注道招网公众帐号
道招开发者二群