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

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

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

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

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

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

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

// 表单校验源码
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;
	}
},
复制代码

官网的示例是这样的element-ui

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源码里面剩下的就很少了。只剩下如下三个方法了,放一块儿吧。promise

// 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-itemasync

  1. 重置表单:就是让里面每一个item各自重置本身便可。
  2. 清空校验:支持清空针对某个prop的校验,能够是字符串,也能够是数组。若是什么都不传的话,就去状况整个表单的校验了。
  3. 单独校验某个item,根据传入的prop过滤出对应的field,若是有多个只取第一个,而后校验,执行回调。

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

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

el-form的源码应该是讲的很清楚了,有须要的同窗能够查看源码。ui

相关文章
相关标签/搜索