1. 程式人生 > 其它 >form表單驗證及相關拓展(動態驗證)

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
              }
            })
          }       
      },