Vue自定义组件使用Element-ui表单校验

一般情况下(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,而这个方法需要在onFieldBluronFieldChange这两个回调函数里触发,而这两个函数的触发方式是通过在addValidateEvents中监听el.form.blurel.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.blurel.form.change两个事件,想要触发校验,必须要由ElFormItem组件发布这两个事件。

所以得出结论,因为在我们自定义的组件内部没有触发el.form.blurel.form.change这两个事件,所以想要使用 el-form, el-form-item 组件的表单校验功能,组件内部必须要用包裹它的el-form-item组件$emit el.form.blurel.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表单校验的问题了。

效果图

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容