element-ui表单的多层循环验证处理

5,673 阅读2分钟

当时在使用element-ui开发后台项目的时候,遇到表单中数组字段需要验证,试了好几种写法都没能弄出来,甚至当时都没想到该怎么描述去百度搜索别人的经验借鉴一下,现在我将这个现象记录下来,方便自己,也希望能帮助还没遇到或者即将遇到此问题的你。

当时的需求:

选择允许加床数量,会自动创建选中数量的加床模板,加床模板字段包含加床类型、是否免费。加床模板其实就是一个对象数组,每个对象中的字段(加床类型、是否免费)同时也需要验证。

先贴个效果截图 1621224041(1).png

下面贴上部分源码,后面再解释一下:

form4.vue中需要验证的部分代码

<el-form 
  :model="form" 
  label-position="top"
  v-show="stepIndex==0"
  ref="formRef"
 >
    <template v-if="form.allowExtraBed == 1">
      <el-form-item
        label="允许加床数量"
        prop="extraBedNum"
        label-width="280px"
        verify
      >
        <el-select
          v-model="form.extraBedNum"
          placeholder="请选择"
          @change="onExtraBedNumChange"
          clearable
        >
          <el-option
            v-for="its in [1, 2, 3, 4, 5]"
            :key="its"
            :label="its"
            :value="its"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <div v-for="(item, index) in form.extraBedData" :key="index">
        <div class="area-wrapper">
          <h3>加床{{ index + 1 }}</h3>

          <el-form-item
            label="加床类型"
            :prop="`extraBedData.${index}.extraBedType`"
            verify
          >
            <el-select
              v-model="item.extraBedType"
              placeholder="请选择"
              style="width: 100%"
              clearable
            >
              <el-option
                v-for="item in dict.extra_bed_type"
                :key="item.dataValue"
                :label="item.dataName"
                :value="item.dataValue"
              >
              </el-option>
            </el-select>
          </el-form-item>

          <el-form-item
            label="是否免费"
            :prop="`extraBedData.${index}.free`"
            verify
          >
            <el-select
              v-model="item.free"
              placeholder="请选择"
              style="width: 100%"
              clearable
            >
              <el-option
                v-for="item in [
                  { dataName: '是', dataValue: 1 },
                  { dataName: '否', dataValue: 0 },
                ]"
                :key="item.dataValue"
                :label="item.dataName"
                :value="item.dataValue"
              >
              </el-option>
            </el-select>
          </el-form-item>

          <el-form-item
            v-if="item.free == 0"
            label="加床价格"
            :prop="`extraBedData.${index}.extraBedFee`"
            :verify="{ type: 'pint', lte: 999 }"
          >
            <el-input placeholder="请输入内容" v-model="item.extraBedFee">
              <template slot="append">/元</template>
            </el-input>
          </el-form-item>
        </div>
      </div>
    </template>
</el-form>  

**大家注意,其实多层循环验证关键就是在 el-form-item 上 的

:prop="`extraBedData.${index}.extraBedType`"   // 推荐写法
// :prop="'extraBedData'+index+'.extraBedType'" // 不推荐写法

extraBedData就是数组名,index是数组循环索引值,extraBedType为需要验证的字段。

总结起来就是:

:prop="`数组字段.${数组循环索引值}.数组对象中待验证字段`"
// :prop="'数组字段.' + 数组循环索引值 + '数组对象中待验证字段'"

遇到问题不要慌,多想想,查查资料,或者请教下同事朋友,困难并不可怕。

哦,对了,大家是否看到了我代码中的verify,这是我们公司的几位小伙伴基于element-ui开发的一款表单验证插件,很实用,在npm中搜索 element-verify 可查看其文档。有兴趣的可以下载使用,当然你直接使用element-ui提供的rules来验证也是没有任何问题的,譬如上面的

<el-form-item
    label="是否免费"
    :prop="`extraBedData.${index}.free`"
    verify
>
</el-form-item>

就可以这样写

 <el-form-item
    label="是否免费"
    :prop="`extraBedData.${index}.free`"
    :rules="{
        required: true,
        message: '必填项',
    }"
>
</el-form-item>

一般饿了么表单都是提交表单时,通过 validate 对整个表单进行校验的,

this.$refs.formRef.validate(valid => {
    if (valid) {
    }
})

如果要对部分表单字段进行校验,我们使用validateField即可。比如我要对form.name中的name字段单独进行验证,

this.$refs.formRef.validateField("name")

如果我要单独验证的是一个数组对象中的某个字段呢,又该如何实现呢?

let lists = this.formData.targetList;
targetList.forEach((item, index) => {
  this.$refs.formDialogRef.validateField(
    `targetList.${index}.targetChildField`
  );
});

想了解更多,可阅读我另一篇文章 ,点此进入

好了,关于多层循环验证的问题就啰嗦到这里啦。

下面记录下这个页面完整的js,当然,跟我们讨论的问题无关啦,大家可以略过。

import { mapGetters } from "vuex";
export default {
  props: {
    form: {
      type: Object,
      required: true,
      default() {
        return {};
      },
    },
    status: {
      type: String,
      required: true,
    },
  },
  computed: {
    ...mapGetters(["dict"]),
  },
  data() {
    return {};
  },
  watch: {
    // 是否允许加床选择否,清空加床信息、加床数量
    "form.allowExtraBed": {
      handler(nv, ov) {
        if (nv == 0) {
          this.$set(this.form, "extraBedData", []);
          this.$set(this.form, "extraBedNum", null);
        }
        if (nv == 1) {
          if (
            !this.form.extraBedData ||
            (this.form.extraBedData.constructor === Array &&
              this.form.extraBedData.length == 0)
          ) {
            this.$set(this.form, "extraBedNum", 1);
            this.onExtraBedNumChange(1);
          }
        }
      },
      immediate: true,
      deep: true,
    },
  },
  methods: {
    onExtraBedNumChange(nv) {
      let temp = [];
      for (let i = 0; i < nv; i++) {
        temp.push({
          extraBedType: null,
          free: null,
          extraBedFee: null,
        });
      }
      this.$set(this.form, "extraBedData", temp);
    },
  },
};