form表單驗證及相關拓展(動態驗證)
阿新 • • 發佈:2022-05-31
一、前言
最近遇到兩個需求,一個是需要對一個表格動態生成的表單項進行校驗,還有一個是對動態生成的多個表單進行校驗。關於表單的動態校驗,這個elementui文件上也有說明傳送任意門,其他拓展的沒有詳細講解,所以本篇隨筆主要是對錶單校驗進行一個總結,以便後續回顧。
二、普通的表單驗證
這種表單驗證官方文件上寫的很詳細, 只需注意將Form-Item 的 prop
屬性設定為需校驗的欄位名即可。
rules: { name: [ { required: true, message: '請輸入活動名稱', trigger: 'blur' }, { min:View Code3, 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' } ] }
如果預設的校驗規則滿足不了需求還可以通過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>
三、多表單的迴圈校驗
需要注意的點:
- el-form標籤的ref需使用動態屬性,如:ref="'xxx'+i"的形式;
- 在使用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
}
})
}
},