el-form 表单校验 异步问题 解决

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了el-form 表单校验 异步问题 解决相关的知识,希望对你有一定的参考价值。

参考技术A

问题描述:
一个新增页面里有多个组件,在新增页面对组件进行 校验 必填项等,发现效验有异步问题;
之前写法

异步原因:表单中有级联,下拉框等,是需要调接口的,需要时间,就会异步;
解决问题方法:使用 Promise

动态生成的表单如何用 el-form 校验,你知道吗?

背景

Vue 的 el-form 提供了表单校验功能,常规用法是用 :rules 属性设置校验规则,并通过 el-form-item 的 prop 属性绑定校验规则。但是有一种情况,如果表单位于 v-for 标签中,是动态生成的,该怎么使用 el-form-item 来校验呢?

此外,如果待校验的表单是 el-popover 组件中的 readonly 表单,blur 触发不稳定,该怎么处理呢?

本文继续分享这两个问题的解决办法。

v-for 遍历的表单校验

根据官网的介绍,是在 el-form-item 中使用 :rules 属性,同时 prop 属性直接定位到具体循环元素。这个用法的前提是在循环外面包裹一个 el-form 元素,v-for 位于 el-form-item 中。

<el-form :model="dynamicValidateForm" ref="dynamicValidateForm" label-width="100px" class="demo-dynamic">
  <el-form-item prop="email"  label="邮箱"  :rules="[
       required: true, message: '请输入邮箱地址', trigger: 'blur' ,
       type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] 
    ]"
  >
    <el-input v-model="dynamicValidateForm.email"></el-input>
  </el-form-item>
  <el-form-item
    v-for="(domain, index) in dynamicValidateForm.domains"
    :label="'域名' + index"
    :key="domain.key"
    :prop="'domains.' + index + '.value'"
    :rules="
      required: true, message: '域名不能为空', trigger: 'blur'
    "
  >
    <el-input v-model="domain.value"></el-input><el-button @click.prevent="removeDomain(domain)">删除</el-button>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="submitForm('dynamicValidateForm')">提交</el-button>
    <el-button @click="addDomain">新增域名</el-button>
    <el-button @click="resetForm('dynamicValidateForm')">重置</el-button>
  </el-form-item>
</el-form>

位于循环中的 el-form-item ,为 el-form-item 设置 :rules 属性,同时设置它的 prop 属性需要遵循的规则为:

   prop=循环对象.下标.子属性

运行效果:

通过反复测试,我发现了一种更简单的方法,就是 v-for 针对 el-from ,每个循环的本质就是一次独立的 el-form 校验,这就跟普通表单的校验没啥区别了,容易写也好理解。

循环内部创建 el-form 表单校验

这种方法是在 v-for 语句内部,循环创建 el-form 表单,它的 modle 指向当前循环的元素,它内部的 el-form-item 直接引用当前循环元素的子属性即可。

例如,下面这个功能配置页面,每个规则包含三项信息名称、分类、相关字段:

校验时,将每个规则的配置信息包裹在一个 el-form 中,就跟普通表单校验一样。

首先,定义 rules 对象:

rules1: 
        name: [
           required: true, message: '请输入业务名称', trigger: 'blur' ,
        ],
        typeName: [
           required: true, message: '请选择分类', trigger: 'change' ,
        ],
        relation: [
           required: true, message: '请选择字段', trigger: ['blur', 'change'] ,
        ],
      ,

接着,编写 el-form 和 el-form-item ,设置校验属性:

<el-row  :key="index"   v-for="(item,index) in data.rules">
   <el-col :span="20" >
	<el-form  :model="item"  :rules="rules1" :ref="`ruleForm$index`">
	  <el-form-item label="业务名称:" prop="name"   >
	    <el-input clearable v-model="item.name"/>
	  </el-form-item>
	  <el-form-item label="所属分类:" prop="typeName"  >
	    <el-popover  rigger="click" placement="bottom">
		<el-tree
		  :ref="`tree$index`"
		  :data="typeInfos"
		  node-key="name"
		  :current-node-key="item.typeName"
		  :props="defaultProps"
		  :filter-node-method="filterNode"
		  @node-click="changeFieldSelector(index)">
		</el-tree>
	      <el-input v-model="item.typeName" readonly placeholder="选择分类" >
	      </el-input>
	    </el-popover>
	  </el-form-item>
	  <el-form-item  prop="relation" label="相关字段:"  :label-width="formLabelWidth">
	    <el-select clearable v-model="item.relation " placeholder="选择字段">
	    </el-select>
	  </el-form-item>
	</el-form>
             
      <i class="el-icon-circle-plus-outline"   @click="addRule(index)"/>
      <i class="el-icon-circle-close"   @click="deleteRule(index)"/>
    </el-col>
  </el-row>

核心思路是,在每一轮 v-for 中,创建 el-form ,model 指向的是 v-for 的迭代元素 item:

  1. v-for=“(item,index) in data.rules”
  2. 内部的引用迭代对象: el-form :model=“item” :rules=“rules1”
  3. el-from-item 正常引用 item 的属性:

最后,保存时循环触发各个 el-form 的校验:

 // 触发各部分的表单的校验操作
 for (let i = 0; i < this.data.rules.length; i += 1) 
   this.$refs[`ruleForm$i`][0].validate((valid) => 
     if (!valid) 
       isOk = false;
       return false;
     
     return true;
   );
 

prop 属性指定异常

循环内部指定 prop 时,容易出现这个异常:

也就是说 el-form-item上的属性 prop字段,必须是其父级组件 el-form 中绑定 model 字段的直接子属性。

所以,用官网推荐的循环的方式,必须小心 prop 赋值,保证每个 el-form-item 的 prop 与 rules 对象中的属性一致。

校验表单位于 el-popover 中

如果校验的表单是 el-popover 弹出选项的 readonly 表单,该怎么校验呢?

前面例子中的第二个表单 “所属分类” 是一个弹出树选择组件,选中树节点后将值绑定到一个 readonly 表单,这个表单才是我们要验证的。这时存在一种问题:这个只读组件的 onblur 触发校验后,即使通过弹框选择了元素,错误信息还是无法消失。

为了解决这个问题,可以在 el-tree 的选中事件中手动触发一次校验:

changeFieldSelector(index)  // 数据名称树节点选中时触发的方法
      const tree = this.$refs[`tree$index`];
      // 因为 el-tree 是在 v-for 中,VUE 用了数组存储,所以需要再取【0】得到 el-tree 对象
      const data = tree[0].currentNode.node.data;
      console.log(`点击了第$index + 1个节点的日志类型,选中的类型是 $data.name`);

      Vue.set(rule, 'typeName', data.typeName);
      Vue.set(rule, 'type', data.type);

      // 手动触发 readonly 表单校验
      this.$refs[`ruleForm$index`][0].validate((valid) => 
        if (!valid) 
          return false;
        
        return true;
      );
    ,

启示录

文本介绍了三个表单校验的问题,补充上一节的内容,比官网的介绍都还要完整

  1. v-for 动态生成的表单校验,如何校验
  2. please transfer a valid prop path to form item 属性绑定问题;
  3. 位于 el-popover 中的 readonly 属性,如何进行校验

以上是关于el-form 表单校验 异步问题 解决的主要内容,如果未能解决你的问题,请参考以下文章

el-form的各种校验姿态

Element-UI中el-form 表单如何校验

Element-UI中el-form 表单如何校验

Element-UI中el-form 表单如何校验

element-ui使用form表单校验

el-form 多层级表单