非el组件/自定义组件触发el-form的校验
参考文档:https://zhuanlan.zhihu.com/p/390466860
问题描述
非el组件像原生的input
、自定义组件等,无法触发el-form
的rules校验,如下面的代码:
<el-form ref="passwordForm"
:model="passwordForm"
:rules="rules">
<el-form-item label="密码"
prop="oldPassword">
<el-input type="password" auto-complete="off"
v-model="passwordForm.oldPassword" />
</el-form-item>
<el-form-item label="新密码"
prop="newPassword">
<password-input v-model="passwordForm.newPassword" />
</el-form-item>
<el-form-item label="确认新密码"
prop="newPasswordCheck">
<password-input v-model="passwordForm.passwordCheck" />
</el-form-item>
</el-form>
export default {
data() {
var validatePasswordCheck = (rule, value, callback) => {
if (value !== this.passwordForm.newPassword) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}
return {
passwordForm: {
oldPassword: '',
newPassword: '',
newPasswordCheck: ''
},
rules: {
oldPassword: [
{ required: true, message: '请输入密码', trigger: 'blur' }
],
newPassword: [
{ required: true, message: '请输入新密码', trigger: 'blur' }
],
newPasswordCheck: [
{ required: true, message: '请再次输入新密码', trigger: 'blur' },
{ validator: this.validatePasswordCheck, trigger: 'blur' }
]
}
}
}
}
第一个el-form-item
的el-input
组件可以触发校验,但是第二个和第三个el-form-item
的password-input
是自定义组件,无法触发校验。
源码分析
源码地址: https://github.com/ElemeFE/element
在packages/form/src/form-item.vue中,可以找到addValidateEvents
方法,该方法是用来给el-form-item
的子组件绑定校验事件的,如下:
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);
}
}
在packages/input/src/input.vue
中,可以找到el-input
发送el.form.blur
和el.form.change
事件的代码,这里只贴出el.form.change
的代码:
watch: {
value(val) {
this.$nextTick(this.resizeTextarea);
if (this.validateEvent) {
this.dispatch('ElFormItem', 'el.form.change', [val]);
}
}
}
这里用了dispatch
方法,该方法的代码在src/mixins/emitter.js
中:
dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root;
var name = parent.$options.componentName;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.componentName;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
}
}
由此可以看出,要触发el-form
的校验,需要el-form-item
中的子组件去发布el.form.change
或el.form.blur
等事件,由el-form-item
监听该事件,触发表单校验。
解决方案
- 方法一:在父页面中直接调用表单的校验方法
validateField
:
watch: {
'passwordForm.newPassword': function() {
this.$refs.passwordForm.validateField('newPassword')
}
}
- 方法二:在父页面中发布组件的
el.form.change
等事件:
<input ref="input" @blur="handleBlur">
<script>
export default {
methods: {
handleBlur (val) {
this.$refs.input.$emit('el.form.blur', val)
}
}
}
</script>
- 方法三:在子组件中发布
el.form.change
等事件,此时无需在父页面中做任何处理,其中dispatch
方法直接将上面所说的emitter.js
中的代码拷贝过来即可:
export default {
methods: {
dispatch(componentName, eventName, params) {
// ... 从emitter.js中拷贝过来的代码
},
handleInput (e) {
this.$emit('input', e.target.value)
this.dispatch('ElFormItem', 'el.form.change', [e.target.value])
}
}
}
得到的效果如下图所示:
不过输入框的颜色没变成红色,查看el-input
的样式可以看到其错误时的颜色是通过.el-form-item.is-error .el-input__inner
选择器来控制的:
.el-form-item.is-error .el-input__inner, .el-form-item.is-error .el-input__inner:focus, .el-form-item.is-error .el-textarea__inner, .el-form-item.is-error .el-textarea__inner:focus, .el-message-box__input input.invalid, .el-message-box__input input.invalid:focus {
border-color: #F56C6C;
}
类似的,可以给自定义组件也加上el-input__inner
类名,便能实现错误时的样式了。
效果如下图所示: