vue3 通过v-for循环的动态el-form表单渲染和验证

268 阅读1分钟

el-form-item多级遍历

image.png

<template>
    <div class="card">
        <div>
            <el-button type="primary" @click="handleAdd">+新增</el-button>
        </div>
        <el-form ref="formRef" :model="form">
            <div v-for="(item, index) in form.data" :key="index" class="form-view">
                <el-form-item
                    :label="`姓名-${index}`"
                    :prop="`data.${index}.name`"
                    :rules="rules.name"
                    label-width="80px"
                >
                    <el-input v-model="item.name"></el-input>
                </el-form-item>
                <el-form-item label="年龄" :prop="`data.${index}.age`" :rules="rules.age" label-width="80px">
                    <el-input v-model="item.age"></el-input>
                </el-form-item>
                <el-form-item label="是否开关" :prop="`data.${index}.isSwitch`" label-width="80px">
                    <el-switch v-model="item.isSwitch" @change="(e) => handleSwitch(e, index)"></el-switch>
                </el-form-item>
                <template v-if="item.isSwitch">
                    <div class="map-box" v-for="(mm, ii) in form.data[index].mapList">
                        <el-form-item label="mapKey" :prop="`data.${index}.mapList.${ii}.mapKey`" :rules="rules.mapKey">
                            <el-input v-model="mm.mapKey"></el-input>
                        </el-form-item>
                        <el-form-item
                            label="mapValue"
                            :prop="`data.${index}.mapList.${ii}.mapValue`"
                            :rules="rules.mapValue"
                        >
                            <el-input v-model="mm.mapValue"></el-input>
                        </el-form-item>
                        <el-form-item>
                            <el-icon
                                color="#409efc"
                                style="margin-left: 12px; margin-right: 6px"
                                :size="24"
                                @click="handleDeleteMap(index, ii)"
                                ><Remove
                            /></el-icon>
                            <el-icon
                                v-show="form.data[index].mapList.length - 1 === ii"
                                color="#409efc"
                                :size="24"
                                @click="handleAddMap(index)"
                                ><CirclePlus
                            /></el-icon>
                        </el-form-item>
                    </div>
                </template>
                <span class="form-delete-icon">
                    <el-icon color="#F56C6C" :size="24" @click="handleDelete(index)"><DeleteFilled /></el-icon>
                </span>
            </div>
        </el-form>
        <div style="text-align: right">
            <el-button type="primary" @click="submitForm(formRef)">保存</el-button>
        </div>
    </div>
</template>

<script setup lang="ts">
import { reactive, ref } from 'vue'
import { FormInstance, FormRules, ElMessage } from 'element-plus'

const formRef = ref<FormInstance>()
const rules = reactive<FormRules>({
    name: [{ required: true, message: '请输入姓名', trigger: ['blur', 'change'] }],
    age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
    mapKey: [{ required: true, message: '请输入mapkey', trigger: 'blur' }],
    mapValue: [{ required: true, message: '请输入mapValue', trigger: 'blur' }],
})
const form = reactive<any>({
    data: [],
})
const handleAdd = () => {
    form.data.push({
        name: '',
        age: '',
        mapList: [],
    })
}
const handleDelete = (index: number) => {
    form.data.splice(index, 1)
}

const handleAddMap = (index: number) => {
    form.data[index].mapList.push({
        mapKey: '',
        mapValue: '',
    })
}

const handleDeleteMap = (index: number, ii: number) => {
    if (form.data[index].mapList.length === 1) {
        ElMessage.error('至少保留一个map')
        return
    }
    form.data[index].mapList.splice(ii, 1)
}
const handleSwitch = (e: any, index: number) => {
    console.log(e, '==')
    if (e) {
        handleAddMap(index)
    } else {
        form.data[index].mapList = []
    }
}

const submitForm = async (formEl: FormInstance | undefined) => {
    console.log(formRef, 'formRef==')
    console.log(form.data, 'form.data==')

    if (!formEl) return
    await formEl.validate((valid, fields) => {
        if (valid) {
            console.log('submit!')
        } else {
            console.log('error submit!', fields)
        }
    })
}
</script>

<style lang="scss">
.form-view {
    background-color: #f5f5f5;
    border-radius: 4px;
    padding: 20px;
    margin: 10px 0;
    position: relative;
    .form-delete-icon {
        position: absolute;
        right: -10px;
        top: -10px;
        cursor: pointer;
    }
}
.map-box {
    display: flex;
    align-items: center;
    padding-left: 80px;
    svg {
        cursor: pointer;
    }
}
</style>