让 el-form 控制自定义表单组件的状态
使用过 ElementUI 的表单组件的都知道,在 el-form 中设置属性 disabled 为 true 时,整个表单都会被 disabled 掉,那么想要自定义的组件也能跟随 el-form 的设置而变化,该怎么做呢?
我们看一下 el-input 组件的源码,发现有这一段代码:
可以看到除了 el-input 组件自身 props 提供的 disabled 参数以外,还有来自 this.elForm 的 disabled 的值。而它是通过 Vue 的依赖注入分别在 el-form 和 el-form-item 组件中 inject 进来的:
所以,为了自定义的组件也可以被 el-form 组件的状态所控制,实现的自定义的组件如下所示:
<template>
<div class="custom-input">
<input v-model="modelValue" type="text" :disabled="inputDisabled" />
</div>
</template>
<script>
export default {
name: 'CustomInput',
model: { prop: 'value', event: 'change' },
props: {
value: { type: String, default: '' },
disabled: { type: Boolean, default: false }
},
inject: {
elForm: {
default: ''
},
elFormItem: {
default: ''
}
},
computed: {
modelValue: {
get() {
return this.value
},
set(val) {
this.$emit('change', val)
}
},
inputDisabled() {
return this.disabled || (this.elForm || {}).disabled
}
}
}
</script>
把这个组件与 el-input 组件一起对比来使用:
<template>
<div class="container">
<el-form :model="form" :disabled="formDisabled" label-width="auto">
<el-form-item label="el-input" prop="text1">
<el-input v-model="form.text1" />
</el-form-item>
<el-form-item label="custom-input" prop="text2">
<custom-input v-model="form.text2" />
</el-form-item>
</el-form>
<el-button type="primary" @click="formDisabled = !formDisabled">{{ formDisabled ? '取消' : '禁用' }}</el-button>
</div>
</template>
<script>
import CustomInput from './custom-input.vue'
export default {
name: 'Test',
components: { CustomInput },
data() {
return {
form: { text1: '', text2: '' },
formDisabled: false
}
}
}
</script>
<style lang="scss" scoped>
.container {
width: 500px;
margin: 30px auto;
}
</style>
效果如下所示:
实现自定义组件的验证功能
接下来,来看看怎么实现自定义组件的验证功能。在 el-input 组件源码中,有如下实现:
在 el-input 组件源码中没有找到 dispatch 函数的定义,但是可以找到如下代码:
在 emitter 文件中找到了 dispatch 函数的定义,由此可知,它是通过 mixin 混入进来的。作用是为了不断往上查找父组件,直到父组件为指定 componentName 为止,在这里父组件为 el-form-item。找到之后就触发相应的 eventName 事件,并将参数传入执行,该事件触发后,就会被 el-form-item 组件捕获,由此触发相关验证。其代码如下:
再结合在 el-form-item 的组件源码:
由此可知,想要使用 ElementUI 中 el-form 提供的验证功能,自定义组件需要首先引入 emitter 文件,然后在组件的 change 和 blur 事件中,使用 emitter 提供的 dispatch 方法,并通过规定的格式传入相应的参数即可。完整实现代码如下:
<template>
<div class="custom-input">
<input v-model="modelValue" type="text" :disabled="inputDisabled" @blur="onInputBlur" />
</div>
</template>
<script>
import emitter from 'element-ui/lib/mixins/emitter'
export default {
name: 'CustomInput',
mixins: [emitter],
model: { prop: 'value', event: 'change' },
props: {
value: { type: String, default: '' },
disabled: { type: Boolean, default: false }
},
inject: {
elForm: {
default: ''
},
elFormItem: {
default: ''
}
},
computed: {
modelValue: {
get() {
return this.value
},
set(val) {
this.dispatch('ElFormItem', 'el.form.change', [val])
this.$emit('change', val)
}
},
inputDisabled() {
return this.disabled || (this.elForm || {}).disabled
}
},
methods: {
onInputBlur() {
this.dispatch('ElFormItem', 'el.form.blur', [this.modelValue])
}
}
}
</script>
<style lang="scss">
// 设置验证不通过的样式
.el-form-item.is-error {
.custom-input input {
outline-color: #f56c6c;
border-color: #f56c6c;
}
}
</style>
将这个自定义组件引入,并与 el-input 组件一起对比使用如下:
<template>
<div class="container">
<el-form ref="formRef" :model="form" :rules="formRules" :disabled="formDisabled" label-width="auto">
<el-form-item label="el-input" prop="text1">
<el-input v-model="form.text1" />
</el-form-item>
<el-form-item label="custom-input" prop="text2">
<custom-input v-model="form.text2" />
</el-form-item>
<el-form-item>
<el-button type="danger" @click="onValidateForm">验 证</el-button>
</el-form-item>
</el-form>
<el-button type="primary" @click="formDisabled = !formDisabled">{{ formDisabled ? '取消' : '禁用' }}</el-button>
</div>
</template>
<script>
import CustomInput from './custom-input.vue'
export default {
name: 'Test',
components: { CustomInput },
data() {
const validate = (rule, val, cb) => (val.length < 6 ? cb(new Error('长度不能小于六位!')) : cb())
return {
form: { text1: '', text2: '' },
formDisabled: false,
formRules: {
text1: [
{ required: true, message: '请输入', trigger: 'blur' },
{ validator: validate, trigger: 'change' }
],
text2: [
{ required: true, message: '请输入', trigger: 'blur' },
{ validator: validate, trigger: 'change' }
]
}
}
},
methods: {
onValidateForm() {
const { formRef } = this.$refs
if (formRef) formRef.validate()
}
}
}
</script>
<style lang="scss" scoped>
.container {
width: 500px;
margin: 30px auto;
}
</style>
效果如下所示: