随风丶逆风 2020-04-03 15:36:41  2208  收藏 3
分类专栏: Vue 随笔 文章标签: 动态验证 el-form elementUI 表单验证

在上一篇《vue elementUI组件表单动态验证失效的问题与解决办法》中,讲到直接修改prop属性,未触发form-item的重新渲染,所以虽然有校验*的标志,实际上并不会校验。这是表面现象,最近有了空余时间,去看看了element form组件的源码,找到了根本原因。

源码分析

  1. form组件的created钩子函数中添加了el.form.addFieldel.form.removeField事件监听,往fields中添加或删除field,校验的时候会遍历fields数组,而field就是form-item的实例。接着查看form-item组件的源码,可以看到在组件挂载后mounted,如果prop属性有值就会触发el.form.addField事件,在组件销毁前beforeDestroy触发el.form.removeField事件。由此可知如果挂载时form-item组件prop属性无值,不会触发el.form.addField
// form.vue
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);
}
});
} // form-item.vue
mounted() {
// 重点挂载前有prop属性,才会触发'el.form.addField'
if (this.prop) {
this.dispatch('ElForm', 'el.form.addField', [this]);
// ...
this.addValidateEvents();
}
},
beforeDestroy() {
this.dispatch('ElForm', 'el.form.removeField', [this]);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  1. form表单校验是调用表单实例的validate方法,去掉边界、合法性判断一类的代码,其核心源码如下,从代码注释中可以知道,form表单的校验方法核心是调用form-item组件实例的validate方法。
// form.vue
methods: {
validate(callback) {
// ...
this.fields.forEach(field => {
// 调用form-item实例的validate方法
field.validate('', (message, field) => {
if (message) {
valid = false;
}
invalidFields = objectAssign({}, invalidFields, field);
if (typeof callback === 'function' && ++count === this.fields.length) {
callback(valid, invalidFields);
}
});
});
}
}, watch: {
// 如果rules有变化,强制更新form-item的校验事件,并触发一次form实例validate方法
rules() {
// remove then add event listeners on form-item after form rules change
this.fields.forEach(field => {
field.removeValidateEvents();
field.addValidateEvents();
}); if (this.validateOnRuleChange) {
this.validate(() => {});
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  1. 最后看form-itemvalidate方法,省略一些逻辑判断和优化代码,其核心是获取form组件的对应属性的rulesform-item自身的rules,生成AsyncValidator校验器的校验规则描述,并进行数据校验。
// form-item.vue
validate(trigger, callback = noop) {
this.validateDisabled = false;
// 获取form组件的对应属性的rules及form-item自身的rules,并根据触发器trigger过滤
const rules = this.getFilteredRule(trigger);
// 判断校验规则,假值或者rules数组为空,则跳过。值得注意的是空对象并不是假值,所以不会跳过
if ((!rules || rules.length === 0) && this.required === undefined) {
callback();
return true;
} this.validateState = 'validating'; // 设置AsyncValidator的校验规则描述
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);
});
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

从上面的第一点中可以看到,因为prop初始值为空字符串'',所以form表单的fileds不会持有该form-item实例,故即使后面修改prop属性,也不会去校验该表单项,导致校验失效。

解决办法

  1. 《vue elementUI组件表单动态验证失效的问题与解决办法》中讲的强制重新渲染form-item,当时不知道根本原因采用的笨办法。
  2. form-item保留prop属性,根据条件动态修改form组件的rules对象。比如下面这样:
watch: {
'formData.age': {
immediate: true,
handler (newVal) {
if (newVal >= 18) {
this.addRule('bankCardNo', [{ required: true, message: '请输入银行卡号', trigger: 'blur' }])
} else {
this.addRule('bankCardNo', [])
}
}
}
} data () {
return {
rules: {}
}
}, methods: {
addRule (prop, rule) {
this.$set(this.rules, prop, rule)
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  1. form-item保留prop属性,根据条件动态修改form-item组件的rules属性。比如下面两种方式,因为rules属性接受数据和对象。
<el-form-item label="银行卡号" prop="bankCardNo" :rules="formData.age >= 18 ? [{ required: true, message: '请输入银行卡号', trigger: 'blur' }] : []">
<el-input v-model="formData.bankCardNo"></el-input>
</el-form-item> <!-- 或者 -->
<el-form-item label="银行卡号" prop="bankCardNo" :rules="formData.age >= 18 ? { required: true, message: '请输入银行卡号', trigger: 'blur' } : []">
<el-input v-model="formData.bankCardNo"></el-input>
</el-form-item>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

总结

终须由浅入深,浮于表面便是管中窥豹,自身还需静下心认真研究

深入了解Element Form表单动态验证问题 转载的更多相关文章

  1. Vue Element Form表单时间验证控件使用

    如果直接使用Element做时间选择器,其规则(rules)不添加type:'date',会提示类型错误,处理这个需要规范值的类型为date. 时间格式化过滤器 import Vue from 'vu ...

  2. Element Form表单实践(下)

    作者:小土豆biubiubiu 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.im/user/58c61b4361ff4b005d9e8 ...

  3. Element Form表单实践(上)

    作者:小土豆biubiubiu 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.im/user/58c61b4361ff4b005d9e8 ...

  4. Element form表单方法resetFields无效

    之前遇到resetFields无效时都是自己手动用this.ruleForm = Object.assign({}, this.ruleForm, this.$options.data().ruleF ...

  5. 重写form 表单的验证信息

    (function($) { var isformValidationPostBack=true; var isformValidation = false; $.extend({ formValid ...

  6. form 表单jquery验证插件使用

    第一部分:表单样式 <form action="#" method="post" id="regist">   <tabl ...

  7. a链接易混淆与form表单简易验证用法详解

    链接可以说遍布互联网,比如你想提供一个可以跳转到百度首页的链接给网友,那么代码如下: <a href="http://www.baidu.com">百度一下,你就知道& ...

  8. WTForms 表单动态验证

    class UserDetails(Form): group_id = SelectField(u'Group', coerce=int) def edit_user(request, id): us ...

  9. form表单点击后验证

    function check(){ var customertype = document.getElementById("customertype"); //alert(cust ...

随机推荐

  1. BUUCTF [极客大挑战 2019]Not Bad

    总的来说这是一个64位orw的题 开头先在主函数里分配了一个很大的空间 1 __int64 __fastcall main(int a1, char **a2, char **a3) 2 { 3 mm ...

  2. Jedis 连接池的基本使用

    jedis直连 每次操作都会创建一个jedis对象,执行完毕后关闭连接后释放,对应的就是一次Tcp连接. jedis连接池 预先生成一批jedis连接对象放入连接池中,当需要对redis进行操作时从连 ...

  3. spring security 继承 WebSecurityConfigurerAdapter 的重写方法configure() 参数 HttpSecurity 常用方法及说明

    HttpSecurity 常用方法及说明 方法 说明 openidLogin() 用于基于 OpenId 的验证 headers() 将安全标头添加到响应 cors() 配置跨域资源共享( CORS ...

  4. Python操作数据库实战

    pymysql # -*- coding: utf-8 -*- """ @Datetime: 2018/12/26 @Author: Zhang Yafei " ...

  5. PPT2010制作清明上河图动画

    原文: https://www.toutiao.com/i6492312556915393038/ 新建一个空白幻灯片 选择"插入"选项卡,"图像"功能组,&q ...

  6. vue实现引用less,sass全局变量

    1.npm install sass-resources-loader --save-dev: 2.build/utils.js中,修改 function resolveResource(name) ...

  7. 基于Dapper的分布式链路追踪入门——Opencensus+Zipkin+Jaeger

    微信搜索公众号 「程序员白泽」,进入白泽的编程知识分享星球 最近做了一些分布式链路追踪有关的东西,写篇文章来梳理一下思路,或许可以帮到想入门的同学.下面我将从原理到demo为大家一一进行讲解,欢迎评论 ...

  8. test_3 简单密码破解

    题目描述:密码是我们生活中非常重要的东东,我们的那么一点不能说的秘密就全靠它了.哇哈哈. 接下来渊子要在密码之上再加一套密码,虽然简单但也安全. 假设渊子原来一个BBS上的密码为zvbo9441987 ...

  9. VUE3 之 表单元素

    1. 概述 老话说的好:行动起来,原地观望是没有用的. 言归正传,今天我们来聊聊 VUE3 的 表单元素. 2. 表单元素 2.1 文本框与数据绑定 <body> <div id=& ...

  10. 在asp.net webfrom 中完成用户自定义导出

    asp.net原生控件实现自定义列导出功能 自定义列实现 最近负责开发公司内部使用的人事信息化系统时,有一个需求是这样的,需要在页面中可以用户每次导出Excel时自定义需要导出哪些列,经过半天的琢磨和 ...