表单的自定义子控件
表单封装之后就会遇到一个古老的问题,需要放进去一个新类型的子控件怎么办?
这在以前都是很头痛的问题,如果是需要修改封装好的代码才可以实现的话,那就太郁闷了。
但是现在在Vue里面,至少有两种解决方案,还都挺优雅的。
用插槽设置自定义组件
Vue的组件有插槽这个功能,一开始还没想起来,这的多谢好友“我滴神”的提醒,才想起来可以用插槽。好吧其实是我以前还不会用插槽。。。
研究了一下官网,又结合 el-input 设置的插槽理解了一下,发现还不难,于是给表单控件设置了这样的插槽。
<el-form
:model="formModel"
:rules="rules"
ref="formControl"
:inline="false"
class="demo-form-inline"
label-suffix=":"
label-width="130px"
size="mini"
>
<el-row>
<!--不循环row,直接循环col,放不下会自动往下换行。-->
<el-col
v-for="(ctrId, index) in formColSort"
:key="'form_'+index"
:span="formColSpan[ctrId]"
>
<el-form-item
:label="getCtrMeta(ctrId).label"
:prop="getCtrMeta(ctrId).colName"
>
<!--判断要不要加载插槽-->
<template v-if="getCtrMeta(ctrId).controlType === 1">
<slot :name="ctrId">父组件没有设置插槽</slot>
</template>
<!--表单item组件,采用动态组件的方式-->
<template v-else>
<component
:is="ctlList[getCtrMeta(ctrId).controlType]"
v-model="formModel[getCtrMeta(ctrId).colName]"
v-bind="getCtrMeta(ctrId)"
@myChange="mySubmit">
</component>
</template>
</el-form-item>
</el-col>
</el-row>
</el-form>
在原先v-for循环的基础上,加上一个判断,根据meta的controlType 来判断,如果=== 1 好的,那么就是要用插槽,然后把控件ID设置给插槽的name属性,这样就可以按照控件ID来加载外部指定的插槽了。
外部使用方法
父组件首先要设置好插槽,这个就可以很随意了,插槽嘛就是可以各种各样的,我们先来个简单的。
<elForm
v-model="model"
v-model:partModel="partModel"
:meta="meta">
<template v-slot:102="">
<h3>这是外面建立的子控件</h3>
<el-input v-model="model.colName" placeholder="请输入内容"></el-input>
</template>
<template v-slot:104="">
<h3>这是外面建立的另一个子控件</h3>
<input type="text">
</template>
</elForm>
用 template 设置好控件ID,这样可以设置多个插槽。
然后再设置一下表单的meta即可
// 设置使用插槽的表单子控件
meta.itemMeta[102].controlId = 102
meta.itemMeta[102].colName = '属性名称'
meta.itemMeta[102].controlType = 1
属性的具体内以后在介绍,总之,不用改表单控件的内部代码,就可以实现随意往里加新的子控件的需求了。
支持验证等功能吗?
测试了一下,支持各种功能,表单数据验证、排序、占位等都是支持的,和表单自带的子控件是一样的功能。
只是 v-model 需要外部设置一下。
这些还要感谢 Vue 和 UI库的强大。
$ref怎么处理?
element的官网例子里面,重置表单用的是Vue2的方式,正巧在Vue 官网看到了$ref的用法,于是改成了Vue3的方式实现重置表单的功能。
// Vue2 的方法
methods: {
resetForm(formName) {
this.$refs[formName].resetFields();
}
}
// Vue3的方法
// 获取 $ref
const formControl = ref(null)
onMounted(() => {
console.log('表单dom', formControl)
})
const resetForm = () => {
// 清空表单
formControl.value.resetFields()
}
这样表的控件就更完善了,另外,过了几天再看代码,居然看不懂了。
源码
https://github.com/naturefwvue/nf-vue-element
最后水一张难看的图片