elementPlus动态表单校验

4,862 阅读1分钟

做过几次动态表单,每次都坎坷解决记忆不深刻,问题都出在最终的表单校验上,特此记录!!! 首先要实现如下效果:

测试.gif

需求描述:需要动态添加/删除表单信息,并添加校验,点击提交,校验通过则输出表单内容。

(代码是vue3+elementPlus+ts实现的,但实现思路与vue2都是通用的,代码略长,仅关注重要的地方即可。 elementPlus官方有提供动态表单实例: element-plus.gitee.io/zh-CN/compo…


  • 重点1,el-form 绑定的model,需要有一个Key,用于prop绑定时对象查找,我把数据放入了dataList.form中,(重点重点!!!)切不可把dataList作为一个数据去遍历,不然prop绑定的数据无处可寻。
  • 重点2,prop绑定的'form[下标].key',不管嵌套几层,遵循这个规则即可,直到一层层追踪到对应的值。请试图根据案例中v-for遍历,去理解下此处的prop绑定
:prop="`form[${listIndex}].secondList[${reportFormIndex}].second[${index}].secondName`"
  • 重点3,确保根据prop绑定的数据,能够找到对应model里面的值

说下自己错误解决思路,以及碰到的问题:

  1. prop绑定:刚开始以为是该对象对应的字段名即可,然后毫无意外的报错了, please transfer a valid prop path to form item!
  2. 那么又想,是不是可以遍历多个el-form,然后动态生成ref作为id,再遍历这多个el-form,进行校验,如你所想,太复杂,方案太绕了!!!

附最终完整代码:

<template>
  <el-form ref="ruleForms" size="small" :model="dataList">
    <el-collapse v-model="activeNames">
      <el-collapse-item
        v-for="(listItem, listIndex) in dataList.form"
        :key="listItem.firstTitleId"
        :name="listItem.firstTitleId"
      >
        <template #title>
          <h2>{{ listItem.firstTitleName }}</h2>
        </template>
        <el-card
          shadow="never"
          v-for="(reportFormItem, reportFormIndex) in listItem.secondList"
          :key="reportFormIndex"
        >
          <template #header>
            <div class="spaceBetween">
              {{ reportFormItem.secondTitleName }}
              <div>
                <el-button
                  type="primary"
                  size="small"
                  @click="addFun(reportFormItem)"
                  >添加变量</el-button
                >
              </div>
            </div>
          </template>
          <el-empty
            :image-size="40"
            v-if="
              !reportFormItem.second || reportFormItem.second.length == 0
            "
          ></el-empty>
          <el-row
            :gutter="40"
            v-for="(formItem, index) in reportFormItem.second"
            :key="index"
          >
            <el-col :span="9" :offset="2">
              <el-form-item
                placeholder="请输入名称"
                :prop="`form[${listIndex}].secondList[${reportFormIndex}].second[${index}].secondName`"
                label="名称"
                :rules="[
                  {
                    required: true,
                    message: '请输入名称',
                    trigger: 'change',
                  },
                ]"
              >
                <el-input v-model="formItem.secondName"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="4">
              <el-link
                type="primary"
                @click="
                  deleteFun(
                    index,
                    listItem.firstTitleId,
                    reportFormItem.secondTitleId,
                    formItem.secondId,
                    reportFormItem.second
                  )
                "
                >删除</el-link
              >
            </el-col>
          </el-row>
        </el-card>
      </el-collapse-item>
    </el-collapse>
  </el-form>
  <div class="textRight">
    <el-button @click="submit" size="small" type="primary" class="block"
      >提交</el-button
    >
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";

export default defineComponent({
  setup() {
    const state = reactive({
      ruleForms:null as any,
      dataList: {
        form: [
          {
            firstTitleId: "fac12713",
            firstTitleName: "一级标题",
            secondList: [
              {
                secondTitleId: "9fad33f5",
                secondTitleName: "二级标题",
                second: [
                  {
                    secondId: "9cdbd43d",
                    secondName: "新增1",
                  },
                ],
              },
            ],
          },{
            firstTitleId: "fac127132",
            firstTitleName: "一级标题2",
            secondList: [
              {
                secondTitleId: "9fad33f5",
                secondTitleName: "二级标题2",
                second: [],
              },
            ],
          },
        ],
      },
      activeNames: "fac12713",
    });

    const deleteFun = (index, firstTitleId, paraId, varId, second) => {
      second.splice(index, 1);
    };

    const addFun = (item) => {
      item.second.push({
        secondType: "",
        secondName: "",
      });
    };

    //保存并下一步
    const submit = async () => {
      state.ruleForms.validate(async (valid: any) => {
          console.log(state.dataList)
      });
    };

    return {
      ...toRefs(state),
      deleteFun,
      addFun,
      submit
    };
  },
});
</script>