element验证原理
问题
1.表单验证的时候调用validate 方法都干了啥
2.为啥我们在使用el-form的时候,例如一个输入框,单选等组件要放在form-item
3.为啥我做校验的时候,当input 内容改变了就能立马校验
表单结构
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model.number="ruleForm.age"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
调用validate 干了什么 ?
调用遍历每个 formItem 然后调用 validate 方法,调用callback, 返回一个promise 对象,参数为表单校验结果
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, invalidFields) { valid ? resolve(valid) : reject(invalidFields); }; }); } 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; } },</code></pre>
注意点
form 组件 在created 中注册两个 emit el.form.addField 和 el.form.removeField
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);
}
});
},
formItem 组件生命周期
mounted() { if (this.prop) { this.dispatch('ElForm', 'el.form.addField', [this]);
let initialValue = this.fieldValue; if (Array.isArray(initialValue)) { initialValue = [].concat(initialValue); } Object.defineProperty(this, 'initialValue', { value: initialValue }); this.addValidateEvents(); } }, beforeDestroy() { this.dispatch('ElForm', 'el.form.removeField', [this]); }</code></pre>
formItem 组件 validate 方法 方法调用的时候,校验错误会显示 提示
validate(trigger, callback = noop) { this.validateDisabled = false; const rules = this.getFilteredRule(trigger); if ((!rules || rules.length === 0) && this.required === undefined) { callback(); return true; }
this.validateState = 'validating'; const descriptor = {}; if (rules && rules.length > 0) { rules.forEach(rule => { delete rule.trigger; }); } descriptor[this.prop] = rules; const validator = new AsyncValidator(descriptor); const model = {}; model[this.prop] = this.fieldValue; validator.validate(model, { firstFields: true }, (errors, invalidFields) => { this.validateState = !errors ? 'success' : 'error'; this.validateMessage = errors ? errors[0].message : ''; callback(this.validateMessage, invalidFields); this.elForm && this.elForm.$emit('validate', this.prop, !errors, this.validateMessage || null); }); },</code></pre>
为什么需要校验的组件需要放在FormItem 中
formItem 组件方法
在mounted 生命周期的时候 注册两个函数 el.form.blur 和 el.form.change,
一旦formItem 中的组件 调用 上述两个方法,通知formItem 校验
addValidateEvents() { const rules = this.getRules();
if (rules.length || this.required !== undefined) { this.$on('el.form.blur', this.onFieldBlur); this.$on('el.form.change', this.onFieldChange); } }, onFieldBlur() { this.validate('blur'); }, onFieldChange() { if (this.validateDisabled) { this.validateDisabled = false; return; } this.validate('change'); },</code></pre>
为啥我做校验的时候,当input 内容改变了就能立马校验
input 组件
<input :tabindex="tabindex" v-if="type !== 'textarea'" class="el-input__inner" v-bind="$attrs" :type="showPassword ? (passwordVisible ? 'text': 'password') : type" :disabled="inputDisabled" :readonly="readonly" :autocomplete="autoComplete || autocomplete" ref="input" @compositionstart="handleCompositionStart" @compositionupdate="handleCompositionUpdate" @compositionend="handleCompositionEnd" @input="handleInput" @focus="handleFocus" @blur="handleBlur" @change="handleChange" :aria-label="label" >
handleBlur(event) { this.focused = false; this.$emit('blur', event); if (this.validateEvent) { this.dispatch('ElFormItem', 'el.form.blur', [this.value]); } },
总结
1.当调用form 的validate是 会遍历每一个formItem,并调用formItem.validate 方法,显示校验结果
2.input,checkbox 组件必须放在formItem, 当其失去焦点的时候,会调用handleBlur,向上通知formItem,进行校验