form表单验证及相关拓展(动态验证)

一、前言

  最近遇到两个需求,一个是需要对一个表格动态生成的表单项进行校验,还有一个是对动态生成的多个表单进行校验。关于表单的动态校验,这个elementui文档上也有说明传送任意门,其他拓展的没有详细讲解,所以本篇随笔主要是对表单校验进行一个总结,以便后续回顾。

二、普通的表单验证

 

 这种表单验证官方文档上写的很详细, 只需注意将Form-Item 的 prop 属性设置为需校验的字段名即可。

rules: {
          name: [
            { required: true, message: '请输入活动名称', trigger: 'blur' },
            { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
          ],
          region: [
            { required: true, message: '请选择活动区域', trigger: 'change' }
          ],
          date1: [
            { type: 'date', required: true, message: '请选择日期', trigger: 'change' }
          ],
          date2: [
            { type: 'date', required: true, message: '请选择时间', trigger: 'change' }
          ],
          type: [
            { type: 'array', required: true, message: '请至少选择一个活动性质', trigger: 'change' }
          ],
          resource: [
            { required: true, message: '请选择活动资源', trigger: 'change' }
          ],
          desc: [
            { required: true, message: '请填写活动形式', trigger: 'blur' }
          ]
        }
View Code

 

 如果默认的校验规则满足不了需求还可以通过validator函数自定义验证规则,例如:

 1 export default {
 2     data() {
 3       var checkAge = (rule, value, callback) => {
 4         if (!value) {
 5           return callback(new Error('年龄不能为空'));
 6         }
 7         setTimeout(() => {
 8           if (!Number.isInteger(value)) {
 9             callback(new Error('请输入数字值'));
10           } else {
11             if (value < 18) {
12               callback(new Error('必须年满18岁'));
13             } else {
14               callback();
15             }
16           }
17         }, 1000);
18       };
19       var validatePass = (rule, value, callback) => {
20         if (value === '') {
21           callback(new Error('请输入密码'));
22         } else {
23           if (this.ruleForm.checkPass !== '') {
24             this.$refs.ruleForm.validateField('checkPass');
25           }
26           callback();
27         }
28       };
29       var validatePass2 = (rule, value, callback) => {
30         if (value === '') {
31           callback(new Error('请再次输入密码'));
32         } else if (value !== this.ruleForm.pass) {
33           callback(new Error('两次输入密码不一致!'));
34         } else {
35           callback();
36         }
37       };
38       return {
39         ruleForm: {
40           pass: '',
41           checkPass: '',
42           age: ''
43         },
44         rules: {
45           pass: [
46             { validator: validatePass, trigger: 'blur' }
47           ],
48           checkPass: [
49             { validator: validatePass2, trigger: 'blur' }
50           ],
51           age: [
52             { validator: checkAge, trigger: 'blur' }
53           ]
54         }
55       };
56     },
View Code

以下几点需要注意:

  • 自定义校验规则中不能直接写return,比如if(!value)return;必须返回一个回调函数callback()(返回callback的入参为空代表校验通过规则,返回含new Error(‘自定义提示’)入参代表校验不通过规则。
  • 必须保证自定义校验规则的每个分支都调用了callback方法,否则会导致el-form组件的validate方法无法进入回调函数,就会提交失败。
 1 submitForm(formName) {
 2     //提交表单进行保存校验
 3    this.$refs[formName].validate((valid) => {
 4    if (valid) {
 5      alert('submit!');
 6    } else {
 7       console.log('error submit!!');
 8       return false;
 9    }
10  });
11 },

二、表格动态添加表单校验

   上面动图为表格内嵌入表单动态添加校验,需要注意的点:动态添加的表单项绑定的prop属性需要用scope.$index区分绑定值,否则会导致每一行的绑定值都是一样的;

 

HTML代码
<el-table :data="dataForm.transferPlanDetails"
                        style="width: 100%;padding:0"
                        stripe
                        border
                        fit
                        class="tabletree"
                        >
                     <el-table-column
                        label="资产类别"
                        min-width="180"
                        :align="DefaultAlignCommon"
                        prop="assetCategoryId"
                        show-overflow-tooltip>
                        <template slot-scope="scope">
                          <el-form-item
                            :prop="'transferPlanDetails.' + scope.$index + '.assetCategoryId'"
                            :rules="[{required: true, message: '请选择资产类别', trigger: ['blur','change']}]"
                          >
                            <treeselect
                              noResultsText="无匹配选项"
                              noOptionsText="暂无数据"
                              append-to-body  
                              z-index="9998"
                              :clearOnSelect="true"
                              :show-count="true"
                              :searchable="true"
                              filter-node-method="filterNode"
                              :options="assetCategoryTree"
                              :normalizer="normalizerAsset"
                              :default-expand-level="1"
                              placeholder="全部"
                              v-model="scope.row.assetCategoryId"
                              @select="handleAssetCategoryId"/>
                          </el-form-item>
                        </template>
                      </el-table-column>
                      <el-table-column
                        label="品牌"
                        min-width="180"
                        :align="DefaultAlignCommon"
                        prop="brand"
                        >
                        <template slot-scope="scope">
                          <!-- <el-select v-model="scope.row.brand" @focus="getDetail(scope.row.assetCategoryId)" clearable placeholder="全部">
                            <el-option v-for="(obj,index) in brandData" :key="index"
                                      :label="obj" :value="obj"></el-option>
                          </el-select> -->
                          <el-form-item
                            :prop="'transferPlanDetails.' + scope.$index + '.brand'"
                            :rules="[{required: true, message: '请选择品牌', trigger: ['blur','change']}]"
                          >
                             //封装的下拉框组件,用来实现与资产类别的下拉框内容联动
                            <unique-select :key="scope.$index"
                            :queryName ='scope.row.assetCategoryId'
                            v-model='scope.row.brand'
                            />
                          </el-form-item>
                        </template>
                        
                      </el-table-column>
                      <el-table-column
                        label="规格型号"
                        min-width="180"
                        :align="DefaultAlignCommon"
                        show-overflow-tooltip
                        prop="specificationModel">
                        <template slot-scope="scope">
                          <el-form-item
                            :prop="'transferPlanDetails.' + scope.$index + '.specificationModel'"
                            :rules="rules.specificaValid"
                          >
                            <el-input v-model="scope.row.specificationModel" clearable></el-input>
                          </el-form-item>
                        </template>
                      </el-table-column>
                      <el-table-column
                        label="数量"
                        min-width="120"
                        :align="DefaultAlignCommon"
                        show-overflow-tooltip
                        prop="quantity">
                        <template slot-scope="scope">
                          <el-form-item
                            :prop="'transferPlanDetails.' + scope.$index + '.quantity'"
                            :rules="rules.quantityValid"
                          >
                            <el-input v-model="scope.row.quantity" clearable></el-input>
                          </el-form-item>
                        </template>
                      </el-table-column>
                      <el-table-column label= "操作" :align="DefaultAlignUnique" min-width="150">
                        <template slot-scope="scope">
                          <el-button type="text" size="mini" @click="addRow(scope.row)" class='el-icon-circle-plus' ></el-button>
                          <el-button type="text" size="mini" @click="deleteRow(scope.$index)" class='el-icon-remove' ></el-button>
                        </template>
                      </el-table-column>
                  </el-table>

 

三、多表单的循环校验

 

 

需要注意的点:

  1. el-form标签的ref需使用动态属性,如:ref="'xxx'+i"的形式;
  2. 在使用validate方法进行校验的时候,$refs[register][0].validate需要加上[0],因为动态生成的表单ref会变成数组,不加[0]会找不到对应的dom树节点。

 

HTML代码
<div v-for="(o,i) in modal.RowSelection" :key="'call_'+i" style="margin-bottom:10px">
               <div class="detail-bor-div">
               <table class="unique-detail-table">
                 <tr>
                   <td width="10%">资产编号</td>     <td width="15%">{{ o.assetLedgerVo.assetCode?o.assetLedgerVo.assetCode:"" }}</td>
                   <td width="10%">资产名称</td>       <td width="15%">{{ o.assetLedgerVo.assetName?o.assetLedgerVo.assetName:"" }}</td>
                   <td width="10%">S/N号</td>     <td width="15%">{{ o.assetLedgerVo.snNum?o.assetLedgerVo.snNum:"" }}</td>
                 </tr>
               </table>
               </div>
               <div class="detail-bor-div"><br/>
            //注意:model绑定的值必须是一个对象
                 <el-form :ref="'dataForm_mul'+i" :rules="rules" :model="modal.formList[i]" label-position="right"
                       label-width="36%">
                   <el-row>
                     <el-col :span="8">
                       <el-form-item label="调入后使用人" prop="afterUserId">
                         <el-select v-model="modal.formList[i].afterUserId" placeholder=" ">
                           <el-option v-for="(obj,index) in userList" :key="index"
                                       :label="obj.userName" :value="obj.userId"></el-option>
                         </el-select>
                       </el-form-item>
                     </el-col>
                     <el-col :span="8">
                       <el-form-item label="调入人" prop="transferInUserId">
                         <el-select v-model="modal.formList[i].transferInUserId" placeholder=" ">
                           <el-option v-for="(obj,index) in userList" :key="index"
                                       :label="obj.userName" :value="obj.userId"></el-option>
                         </el-select>
                       </el-form-item>
                     </el-col>
                     <el-col :span="8">
                       <el-form-item label="调入日期" prop="transferInTime">
                         <el-date-picker
                             v-model="modal.formList[i].transferInTime"
                             type="date" format="yyyy-MM-dd"
                             value-format="yyyy-MM-dd"
                             placeholder="选择日期时间"
                             :picker-options="pickerOptions"
                             @change="handleDateSelect">
                         </el-date-picker>
                       </el-form-item>
                     </el-col>
                   </el-row>
                   <el-row>
                     
                     <el-col :span="8">
                       <el-form-item label="调入后使用部门" prop="transferInDeptId">
                         <el-select
                            v-model="modal.formList[i].transferInDeptId"
                             clearable placeholder=" " filterable
                             @change="handleSelectDept">
                           <el-option
                               v-for="(obj, index) in deptList"
                               :key="'ut' + index"
                               :label="obj.organName"
                               :value="obj.organId"
                               :disabled="obj.status=='ON'?false:true"
                           ></el-option>
                         </el-select>
                       </el-form-item>
                     </el-col>
                     <el-col :span="8">
                      <el-form-item label="调入后存放位置" prop="transferInLocationId" label-width="40%">
                        <treeselect
                             noResultsText="无匹配选项"
                             noOptionsText="暂无数据"
                            :clearOnSelect="true"
                             :show-count="true"
                             :searchable="true"
                             :flat="true"
                            filter-node-method="filterNode"
                             :options="locationTree"
                             :normalizer="normalizerLocation"
                             :default-expand-level="99"
                             placeholder=" "
                             v-model="modal.formList[i].transferInLocationId"
                             @select="handleSetLocationName($event)"/>
                       </el-form-item>
                     </el-col>
                   </el-row>
                  <el-row>
                     <el-col :span="24">
                       <el-form-item label="调入备注" prop="transferInRemark" label-width="12%">
                        <el-input v-model="modal.formList[i].transferInRemark" maxlength="200" show-word-limit></el-input>
                       </el-form-item>
                     </el-col>
                  </el-row>
                </el-form>
                <!-- <multitle ref="multitle" :userLists='userList' :deptLists="deptList"/> -->
              </div>
            </div>
js代码

ok: function () {
        let self=this
        let data2 = {}
        data2.status='mul';
        let arr=[];//保存验证结果
        let flg = true//
        let mulLength = self.modal.RowSelection.length
        console.log("refs0",self.$refs['dataForm_mul0']);
        console.log("refs1",self.$refs['dataForm_mul1']);
    //循环验证每个表单若有一个表单不符合校验标准则提交失败
        for(let i=0;i<mulLength;i++){
            let register = 'dataForm_mul'+i
            self.$refs[register][0].validate((valid) => {
              if (valid) {
                arr.push('true')
                let data = self.modal.formList
                self.$set(data2,'transferRecordId',self.modal.RowSelection[0].transferRecordId)
                if(i == mulLength-1){
                  arr.forEach(el=>{
                    if(el=='false'){
                      flg = false
                    }
                  })
                  if(flg){
                    self.$emit('model-ok', {data:data,data2:data2}) 
                  }
                }
                    
              }
              else{
                arr.push('false')
                console.log("error");
                return
              }
            })
          }       
      },

 

posted @ 2022-05-31 15:01  by十行  阅读(1491)  评论(0)    收藏  举报