1. 需求描述:
- 点击添加行,增加一级目录结构
- 当类型为
object or array
时,点击右侧➕,增加子集 - 点击右侧🚮,删除对应子集
2. 效果图:

3. 代码
3.1 封装组件代码
<template><template v-if="!!currentLevelData.length"><div class="mt10" v-for="(item, index) in currentLevelData" :key="`${deep}-${index}`"><div class="flex flex-align-center"><div class="common mr10 border-box" :style="{ paddingLeft: (deep - 1) * 10 + 'px' }"><a-input v-model:value="item.key" placeholder="请输入key" /></div><div class="type mr10"><a-selectref="select"v-model:value="item.type"class="full-width"@change="handleChange($event, item)"><a-select-option v-for="t in dataType" :value="t" :key="t">{{ t }}</a-select-option></a-select></div><div class="common mr10"><a-textarea:rows="1"placeholder="请输入参考值"v-model:value="item.value":disabled="objectFile.includes(item.type)"/></div><div class="common mr10"><a-textarea :rows="1" placeholder="请输入备注" v-model:value="item.desc" /></div><div class="flex"><delete-outlined class="ml5" @click="deleteTarget(index)" /><plus-outlinedclass="ml5"v-show="objectFile.includes(item.type)"@click="addSubset(item)"/></div></div><template v-if="!!item.child?.length"><CustomInputGroup :deep="deep + 1" :list="item.child" /></template></div></template>
</template>
<script lang="ts" setup>
import CustomInputGroup from './index.vue';
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';const dataType = ['string', 'number', 'boolean', 'object', 'array', 'file']; const props = defineProps({list: {type: Array,default: () => [],},deep: {type: Number,default: 1,},
});const objectFile = ['object', 'array']; interface paramsItem {key: string;type: string;value: string;desc: string;child?: any;
}
const currentLevelData: any = computed(() => {return props.list;
});
function handleChange(type: string, item: any) {if (objectFile.includes(type)) {item.value = '';item.child = [];} else {delete item.child;}
}
function addSubset(item: any) {const lastDeep = props.deep;if (lastDeep == 5) return message.info('最多支持5层结构', 2);item.value = '';item.value = '';item.child.push({key: `params${props.deep + 1}-${item.child.length + 1}`,type: 'string',value: '',desc: '',});
}
function deleteTarget(index: number) {currentLevelData.value.splice(index, 1);
}
function getChildParams() {return currentLevelData.value;
}
defineExpose({addSubset,getChildParams,
});
</script>
<style lang="less" scoped>
.common {width: 135px;
}
.type {width: 100px !important;
}
</style>
3.2 父组件使用
<template><CustomInputGroup ref="paramRef" :list="formState.param" :deep="1" /><a-button class="mt10" type="primary" @click="addLineParam('param')"> 添加行 </a-button>
</template><script>
const formState = ({param:[]
})
function addLineParam(formStateKey: string) {formState[formStateKey].push({key: `params${formState[formStateKey].length + 1}`,type: 'string',value: '',desc: '',});
}
</script>