原因是:显示隐藏用的v-show。如果用v-if则不会有这个问题。
1.v-show 和 v-if的区别
v-show 是会渲染到页面上的,只是加了style="display:none";
v-if 不会渲染到页面上。
他们的用法,建议的是如果切换频繁则用v-show。这样可以省去每次的渲染时间。 而如果渲染后则不再频繁改变,这种用v-if ,这样省去多余的渲染元素,没必要的不会渲染页面。
然而以表单为例,则是特殊的。因为这种显示隐藏,也可能会频繁切换,按照理解为觉得应该用v-show。可是用了v-show,页面会渲染出内容,只是不显示。这种情况,用element的提交,则通过display:none的隐藏也会被判断,所以会报错。这个时候用v-if 更合理。不过这里得了解element的工作方式。
我觉得大多数时候都应该用v-if,比如权限按钮判断的时候,不能把没有权限的HTML暴露在网页中,如果只是静态的文本内容,显示隐藏我觉得可以用v-show。
2.element和vue的关系,代码中如何体现
好奇的问题,element为什么能够被vue使用?如何加载到Vue中的?
其实element跟我们自己写的公共组件一样,它就是我们用的组件,只是被加载到了我们的项目中,加载到Vue对象下。就可以使用了。
先说下,如何找到源码以Form表单为例,element的源码在node_modules下,找到element-ui文件夹。里面包含的lib文件夹是打包后让我们调用的,packages里面是源码。入口是src/index.js,如下图
![](https://img.haomeiwen.com/i23964155/7ffc10e6802cb128.png)
如果看源码的话,可以从packages里面找到form文件夹。里面的index.js 是入口,其他对应的是组件的内容。组件的原理跟我们自己写的button.vue组件是一样的。
![](https://img.haomeiwen.com/i23964155/93734541a8d9bfc0.png)
如果看不懂,要调试,可以从lib下找到form.js。直接加debugger调试,一步步看流程。
再说下vue的大体机制,vue的组件,要知道都是一个VueComponent对象,这个对象继承Vue对象,再继承Object对象。vue 组件的内在关系为最外层的是个组件,里面如果用到子组件,那么就一层层嵌套。会绑定在对象的children对象上。如果当前页面有组件加ref,那么这个组件则会通过$ref直接绑定到根组件上。需要注意的是这个children和ref里面放的都是VueComponent(组件对应的对象),举个例子
![](https://img.haomeiwen.com/i23964155/96d8408307b1d5cf.png)
![](https://img.haomeiwen.com/i23964155/eaa75e78d69c530d.png)
所以vue 把element组件加载后,也是加载在自己的对象下。
最后他们连接在了一起
如果我们是单独引入,我们会在vue的入口main.js中引入组件。用
improt Form,FormItem from 'element-ui';
Vue.use(Form);
Vue.use(FormItem);
对应的Form的入口是
![](https://img.haomeiwen.com/i23964155/993124e6c63fced0.png)
(这里省略一步是Form对应的ELForm。是最外层的入口里面导入的)
Vue.use(Form) 执行的逻辑是,找到Form里面的install。然后把Vue 传递给里面。可以理解为这样调用Form.install(this)。看如上代码,会把这个Form 通过Vue.component 注入到vue中。这样就可以在自己的页面用element组件的方法了。如:
//this.$refs["formInline"] 访问到了这个VueComponent对象, 然后找到对应的方法
this.$refs["formInline"].validate((valid) => {
if (valid) {
console.log(this.formInline);
console.log("submit!");
} else {
console.log("error submit!!");
return false;
}
});
3.element提交判断的逻辑
这里介绍的就是validate方法了。回到element的源码。就是这个form.js里面的validate方法。(form.js是打包后的,对应的是form.vue)沿着这个方法一步步看逻辑即可
// form 里面的
validate: function validate(callback) {
var _this2 = this;
// 先进行一些极端情况的判断
// this.model 指的就是绑定的数据。如果没有绑定数据,则给出警告。
if (!this.model) {
console.warn('[Element Warn][Form]model is required for validate to work!');
return;
}
var promise = void 0;
// if no callback, return promise
if (typeof callback !== 'function' && window.Promise) {
promise = new window.Promise(function (resolve, reject) {
callback = function callback(valid) {
valid ? resolve(valid) : reject(valid);
};
});
}
var valid = true;
var count = 0;
// 如果需要验证的fields为空,调用验证时立刻返回callback
if (this.fields.length === 0 && callback) {
callback(true);
}
// this.fields是在created里面通过注册事件一个一个添加进来的。
// 它代表的是页面里面有prop的el-form-item。
// 这里可以看出,如果用v-show。那么就能获取这个fields。那么下面的循环就会判断当前的字段。
// 所以就会出现,我之前的问题。虽然隐藏了,但是还是会判断。如果用v-if则不会到fields里面,所以数据的rules如何定义并不影响。
// 如果该有的数据都有,那么进入核心代码。
var invalidFields = {};
// debugger
this.fields.forEach(function (field) {
// 这里每一个field 其实就是el-form-item 这个子组件。里面也有对应的validate方法。这里调用的子组件的方法。
// ————> 指向下面的validate方法
field.validate('', function (message, field) {
if (message) {
valid = false;
}
// 合并对象到invalidFields
invalidFields = merge_default()({}, invalidFields, field);
if (typeof callback === 'function' && ++count === _this2.fields.length) {
callback(valid, invalidFields);
}
});
});
if (promise) {
return promise;
}
},
这里我们可以从form-item.vue(跟打包后的js里面的是一样的)里面看验证的方法,如下
// form-item 里面的
validate(trigger, callback = noop) {
this.validateDisabled = false;
// 这里会获取el-form组件里面定义的rules 和 el-form-item上定义的rule。然后合并他们。所以rules 就是应用到这个item上的规则。
// 基础数据的判断
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);
});
},
这里延展一个问题。就是v-show 的时候虽然fields里面有了,但是我们是否可以改变rules,然后让其通过验证。是可以的。虽然不是最好的方法。但是是可以的。要注意改变的时机,是否需要用nextTick。
4. 表单到底应不应该拆分组件
只是个人看法而已。
我觉得如果表单数据比较多。显示隐藏的块比较大。则应该把独立的块作为组件。传数据的话,直接传formInline即可。
另一种公共的肯定要拆出来。
网友评论