个别状况下(form中的组件都是element提供的组件)在应用elm的表单校验时咱们是这么应用的:
// 栗子.vue<template> <el-form :model="formData" :rule="rules" ref="formRef"> <el-form-item prop="inputValue"> <el-input v-model="formData.inputValue"></el-input> </el-form-item> <el-form-item> <el-button @click="submit">提交</el-button> </el-form-item> </el-form></template><script>export default { .......省略 data() { return { formData: { inputValue: '' }, rules: { inputValue: [ { required: true, message: '请输出流动名称', trigger: 'blur' }, ] } } }, methods: { submit() { this.$refs.formRef.validate((valid) => { if (valid) { alert('submit!'); } else { console.log('error submit!!'); return false; } }); } }}</script>
然而当咱们在<el-form-item>
组件中增加自定义的组件时,你还持续依照下面这中用法是有效的,翻阅element-ui源码就能发现其中起因。
element-ui的form组件的表单验证是由<el-form-item>
组件配合触发的,在el-form-item
中的源码如下:
// el-form-item源码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(); // 增加校验事件 }},methods: { onFieldBlur() { // blur 事件回调 this.validate('blur'); // 触发validate }, onFieldChange() { // change事件回调 if (this.validateDisabled) { this.validateDisabled = false; return; } this.validate('change'); // 触发validate }, addValidateEvents() { const rules = this.getRules(); if (rules.length || this.required !== undefined) { this.$on('el.form.blur', this.onFieldBlur); // ****重点****:监听el.form.blur事件,执行onFieldBlur回调 this.$on('el.form.change', this.onFieldChange); } }, 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; // 删除rule对象里的trigger属性,因为validator.validate的配置项里不须要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); // 向外裸露validate事件,就是element-ui form组件API文档里的validate事件 }); }}
从源码能够看出,<el-form-item>
组件触发校验的办法是validate
,而这个办法须要在onFieldBlur
和onFieldChange
这两个回调函数里触发,而这两个函数的触发形式是通过在addValidateEvents
中监听el.form.blur
和el.form.change
事件来触发(源代码:this.$on('el.form.blur', this.onFieldBlur)
),所以归根结底是要触发这两个事件。
在element的el-input, el-select, el-cascader, el-checkbox
等组件的源码中发现了触发校验事件的办法:
// el-input, el-select, el-cascader, el-checkbox 等组件源码(伪代码)<script> export default { ...省略 handleValueBlur(val) { // 组件绑定值发生变化时的回调函数,有的是触发blur事件的回调,有的是触发change事件的 ...省略 this.$emit('blur', val); this.dispatch('ElFormItem', 'el.form.blur', [val]); // 触发blur校验事件 }, handleValueChange(val) { ...省略 this.$emit('change', val); this.dispatch('ElFormItem', 'el.form.change', [val]); // 触发change校验事件 } }</script>
在组件blur或change时除了发送blur和change事件以外还调用了两个dispatch办法,重点来了:this.dispatch('ElFormItem', 'el.form.blur', [val]);
,了解一下dispatch
这个办法吧(相熟公布订阅的选手们对这个名词并不生疏)~ 找到它在element的emitter.js里:
// emitter.jsexport default { methods: { dispatch(componentName, eventName, params) { // @param 1: 触发事件的组件名称 2: 事件名称 3. 额定参数 var parent = this.$parent || this.$root; var name = parent.$options.componentName; while (parent && (!name || name !== componentName)) { // 依据componentName自下而上递归查找指标组件 parent = parent.$parent; if (parent) { name = parent.$options.componentName; } } if (parent) { // 用名称为[componentName]的组件$emit事件 parent.$emit.apply(parent, [eventName].concat(params)); } } }}
综上代码,得悉dispatch
办法是通过指标组件公布事件。 咱们回归方才的代码this.dispatch('ElFormItem', 'el.form.blur', [val]);
和this.$on('el.form.blur', this.onFieldBlur);
就是ElFormItem
中订阅了el.form.blur
和el.form.change
两个事件,想要触发校验,必须要由ElFormItem
组件公布这两个事件。
所以得出结论,因为在咱们自定义的组件外部没有触发el.form.blur
和el.form.change
这两个事件,所以想要应用 el-form, el-form-item
组件的表单校验性能,组件外部必须要用包裹它的el-form-item
组件$emit el.form.blur
和el.form.change
。代码这么写:
// 论断栗子.vue<template> <el-form :model="formData" :rule="rules" ref="formRef"> <el-form-item label="内容" prop="inputValue" ref="inputValueRef"> <!-- 增加ref, 用来调用$emit --> <my-input v-model="formData.inputValue" @blur=“handleBlur”></my-input> </el-form-item> <el-form-item> <el-button @click="submit">提交</el-button> </el-form-item> </el-form></template><script>import MyInput from './MyInput.vue'; // 自定义富文本组件 export default { .......省略 components: {MyInput}, data() { return { formData: { inputValue: '' }, rules: { inputValue: [ { required: true, message: '请输出内容', trigger: 'blur' }, ] } } }, methods: { handleBlur(v) { // 增加blur事件回调,为了emit这个'el.form.blur'事件! this.$refs.inputValueRef.$emit('el.form.blur', v); // 重点! }, submit() { this.$refs.formRef.validate((valid) => { if (valid) { alert('submit!'); } else { console.log('error submit!!'); return false; } }); } }}</script>
最初就能解决自定义组件应用element表单校验的问题了。
效果图: