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-select
ref="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-outlined
class="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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
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>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24