周末在封装一个Form组件,供业务层便捷使用, 父组件:
<CommonForm
v-model="form"
:layout-config="layoutConfig"
:option="option"
@on-success="onSubmitSuccess"
>
</CommonForm>
const form = ref({
subObj:{
title:'清新空气'
}
subObj2:{
status:{
pdstatus:0
}
}
})
const option.value = {
column: [
{
label: '标题',
prop: 'subObj.title',
type: 'input',
},
{
label: '盘点状态',
prop: 'subObj2.status.pdstatus',
type: 'select',
dicCode: 'PdStatus',
},
],
}
子组件用modelValue接收form,且通过遍历循环生成form-item 子组件CommonForm代码:
<template v-for="item in columnItems" :key="item.prop">
<template
v-if="
item.type === TableColumnOrFormTypeEnum.INPUT ||
item.type === TableColumnOrFormTypeEnum.TEXTAREA ||
(!item.type && item.prop)
"
>
<el-form-item
v-if="!item.isShowCallBack || item.isShowCallBack()"
:label="item.label"
:prop="item.prop"
:style="{
flex: setFlex(item),
}"
>
<el-input
v-model="form[item.prop]"
clearable
:disabled="item.disabled"
:placeholder="item.placeholder || '请输入' + item.label"
:readonly="item.readonly"
:type="item.type || 'text'"
/>
</el-form-item>
</template> <template v-if="item.type === TableColumnOrFormTypeEnum.SELECT">
<el-form-item
v-if="!item.isShowCallBack || item.isShowCallBack()"
:label="item.label"
:prop="item.prop"
:style="{
flex: setFlex(item),
}"
>
<CommonSelect
v-model="form[item.prop]"
:dic-code="item.dicCode"
:dic-url="item.dicUrl"
:disabled="item.disabled"
:opition-list="item.opitionList"
:placeholder="item.placeholder || '请选择' + item.label"
:readonly="item.readonly"
/>
</el-form-item>
</template>
</template>
此时子组件无法获取到form子对象的值,因为form[item.prop]实际上是form.['subObj.title'],而实际上我需要的是form.subObj.title或者form['subObj']['title'],然而v-model是非常受限制的,无法支持函数,三目运算符,以及一个变量替换另一个变量。思索之后,得到一个解决方案,则是在当前子组件再封装一层子组件,改变form源到form.subObj,改造子组件CommonForm如下:
<template v-for="item in columnItems" :key="item.prop">
<CommonFormItem v-model="form" :item="item" :set-flex="setFlex" />
<template>
子组件CommonFormItem代码如下:
<template
v-if="
item.type === TableColumnOrFormTypeEnum.INPUT ||
item.type === TableColumnOrFormTypeEnum.TEXTAREA ||
(!item.type && item.prop)
"
>
<el-form-item
v-if="!item.isShowCallBack || item.isShowCallBack()"
:label="item.label"
:prop="item.prop"
:style="{
flex: setFlex(item),
}"
>
<el-input
v-model="form[keys.slice(-1)]"
clearable
:disabled="item.disabled"
:placeholder="item.placeholder || '请输入' + item.label"
:readonly="item.readonly"
:type="item.type || 'text'"
/>
</el-form-item>
</template>
<template v-if="item.type === TableColumnOrFormTypeEnum.SELECT">
<el-form-item
v-if="!item.isShowCallBack || item.isShowCallBack()"
:label="item.label"
:prop="item.prop"
:style="{
flex: setFlex(item),
}"
>
<CommonSelect
v-model="form[keys.slice(-1)]"
:dic-code="item.dicCode"
:dic-url="item.dicUrl"
:disabled="item.disabled"
:opition-list="item.opitionList"
:placeholder="item.placeholder || '请选择' + item.label"
:readonly="item.readonly"
/>
</el-form-item>
</template>
const keys = computed(() => {
const keyArray = props.item.prop?.split('.') || []
return keyArray
})
const getObjectKeyValue = () => {
if (!keys.value || !keys.value.length) return
const { modelValue } = props
const currentKeys = keys.value.slice(0, -1)
if (!currentKeys || !currentKeys.length) {
return modelValue
}
const currentForm = currentKeys.reduce((pre, cur) => {
return pre ? pre[cur] : undefined
}, modelValue)
return currentForm
}
const form = ref(getObjectKeyValue())
子组件CommonFormItem的v-model=form[keys.slice(-1)], 以上keys求出来值为['subObj','titie'] getObjectKeyValue()做的功能则是把form源做修改,标题Item源改为form.subObj以及盘点状态Item的源为form.subObj2.status. 则两个item的v-model的值分别form.subObj['title']和form.subObj2.status['pdstatus'].
完美解决v-mdel对动态传参数,且多层嵌套的不支持的问题