最近一直在做后臺管理項目,自然少不了表單校驗。說說我在表單校驗上遇到的一些難點。
- 在父組件中校驗子組件的信息;
- form表單嵌套表格的校驗信息;
- 表單金額的校驗規則(產品要求輸入最多8位整數,4位小數,最高位不能位0);
首先我們來看父組件如何去校驗子組件中的信息
同一組件內的校驗,都好辦,難的是跨組件校驗。
我們來看有這樣一個場景:有一個編輯和查看的模塊,默認展示查看模塊,通過點擊父組件的‘編輯’按鈕顯示編輯模塊,編輯后,點擊父組件的‘保存’按鈕顯示查看模塊。所以這里點保存時需要去校驗子組件,校驗成功才能調保存接口。
這里我們主要看父組件,和edit組件,read組件只是展示信息的,沒有需要講的地方。
<!-- 父組件 -->
<template>
<div class="father">
<div class="father-btn">
<el-button v-if="!isEdit" @click="isEdit=true" type="primary">編輯</el-button>
<el-button v-if="isEdit" @click="isEdit=false" disabled>取消</el-button>
<el-button v-if="isEdit" type="primary" @click="saveEdit">保存</el-button>
</div>
<div class="father-content">
<edit v-if="isEdit" ref="edit" />
<read v-else />
</div>
</div>
</template>
<!-- 編輯子組件 -->
<template>
<el-form :model="numberValidateForm" ref="numberValidateForm" label-width="100px" class="demo-ruleForm">
<el-form-item
label="年齡"
prop="age"
:rules="[
{ required: true, message: '年齡不能為空'},
{ type: 'number', message: '年齡必須為數字值'}
]"
>
<el-input type="age" v-model.number="numberValidateForm.age" autocomplete="off"></el-input>
</el-form-item>
</el-form>
</template>
// 父組件
import { Component, Vue } from 'vue-property-decorator';
import Read './read.vue';
import Edit './edit.vue';
@Component({
components: {
Edit,
Read,
},
})
export default class Father extends Vue {
private isEdit: boolean = false;
private saveEdit() {
const edit = this.$refs.edit as any;
edit.numberValidateForm.validate((valid) => {
if (valid) {
// 校驗通過拿到子組件的值,通過調用子組件的getData方法
const editData = edit.getData();
console.log(editData);
// 調用保存接口
// ...
this.isEdit = false;
} else {
// 校驗失敗
return false;
}
});
}
}
// edit.vue
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class Edit extends Vue {
private numberValidateForm: any = {
age: '',
};
private getData() {
return numberValidateForm;
}
}
Form表單中嵌套表格的這種校驗又怎么做呢
<template>
<el-form :model="formData" :rules="rules">
<el-table
:data="formData.tableList"
:show-header="false"
style="width: 100%">
<el-table-column>
<template slot-scope="scope">
<el-form-item
:prop="'tableList.' + scope.$index + '.dateTime'"
:rules='rules.dateTime'>
<el-date-picker
v-model="scope.row.dateTime"
size="mini"
type="date"
value-format="timestamp"
placeholder="請選擇日期">
</el-date-picker>
</el-form-item>
</template>
</el-table-column>
<el-table-column>
<template slot-scope="scope">
<el-form-item
:prop="'tableList.' + scope.$index + '.num'"
:rules='rules.num'>
<el-input
type="text"
size="mini"
v-model="scope.row.num">
</el-input>
</el-form-item>
</template>
</el-table-column>
</el-table>
</el-form>
</template>
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class Edit extends Vue {
private formData: any = {
tableList: [
{
dateTime: '',
num: '',
},
{
dateTime: '',
num: '',
},
],
};
get rules() {
const checkDateTime = (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback(new Error('請選擇日期'));
} else {
callback();
}
};
const checkNum = (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback(new Error('請輸入'));
} else if (!new RegExp(/(^[1-9]([0-9]{1,7})$|^[1-9]$)/).test(value)) {
callback(new Error('請輸入1-8位數字'));
} else {
callback();
}
};
const obj = {
dateTime: [
{ validator: checkDateTime, trigger: ['change', 'blur'] },
],
num: [
{ validator: checkNum, trigger: 'blur' },
],
};
return obj;
}
}
嵌套table的校驗有兩個注意點:
- 注意 prop 的綁定方式同一般的不同;
- el-form-item 上除了綁定 prop 還要綁定 rules;
金額和純數字的校驗
<template>
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px">
<el-form-item label="數量" prop="amount">
<el-input
type="text"
:maxlength="8"
onkeypress="return event.keyCode>=48&&event.keyCode<=57"
@keyup.native="checkAmount(ruleForm.amount)"
v-model="ruleForm.amount">
</el-input>
</el-form-item>
<el-form-item label="金額" prop="price">
<el-input
type="text"
@keyup.native="checkPrice(ruleForm.price)"
v-model="ruleForm.price">
</el-input>
</el-form-item>
</el-form>
</template>
import { Component, Vue } from 'vue-property-decorator';
const reg = /(^[1-9]([0-9]{1,7})$|^[0-9]$)/;
const priceReg = /(^[1-9]([0-9]{0,7})$|^[0-9]$|^[0-9](\.[0-9]{0,4})$|^[1-9]([0-9]{0,7})\.[0-9]([0-9]{0,3})$|^[1-9]([0-9]{0,7})\.$)/;
@Component
export default class EllipsisComponent extends Vue {
private ruleForm: any = {
amount: '',
price: '',
};
get rules() {
const checkAmount = (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback(new Error('請輸入'));
} else if (!reg.test(value)) {
callback(new Error('請輸入1-8位數字'));
} else {
callback();
}
};
const checkPrice = (rule: any, value: any, callback: any) => {
if (value == null || value === '') {
callback(new Error('請輸入'));
} else if (!priceReg.test(value)) {
callback(new Error('最多輸入8位整數,4位小數'));
} else {
callback();
}
};
const obj = {
amount: [
{ validator: checkAmount, trigger: 'blur' },
],
price: [
{ validator: checkPrice, trigger: 'blur' },
],
};
return obj;
}
private checkAmount(value: any) {
if (value != null && value.length > 0) {
if (!reg.test(value)) {
if (/[^\d.]+/.test(value)) { // 匹配中間是否插入了字母,等其他字符
this.ruleForm.amount = value.replace(/[^\d.]+/, '');
return;
}
if (/^([0-9]\d{8,}(\.\d*)*)$/.test(value)) { // 匹配是否超過8位
this.ruleForm.amount = value.substring(0, 8);
return;
}
if (/^[0]+/.test(value)) { // 最高位是否為0
this.ruleForm.amount = value.replace(/^[0]+/, '');
return;
}
}
}
}
private checkPrice(value: any) {
if (!priceReg.test(value)) {
if (/^(\.)/.test(value)) { // 匹配第一個字符是否為 .
this.ruleForm.price = value.substring(value.lastIndexOf('.') + 1, value.length);
return;
}
if (/[^\d.]+/.test(value)) { // 匹配中間是否插入了字母,等其他字符
this.ruleForm.price = value.replace(/[^\d.]+/, '');
return;
}
if (/([0-9]\d*)(\.\d*){2,}/.test(value)) { // 匹配是否有多個 . --惡意輸入
this.ruleForm.price = '';
return;
}
if (/^([1-9]\d{8}(\.\d*))$/.test(value)) { // 匹配小數點前是否為7位
this.ruleForm.price = value.replace(value.charAt(value.lastIndexOf('.') - 1), '');
return;
}
if (/^([0-9]\d{9,}(\.\d*)*)$/.test(value)) { // 匹配小數點前是否超過8位-惡意輸入
this.ruleForm.price = '';
return;
}
if (/^([0-9]\d{0,7}(\.\d{5,}))$/.test(value)) { // 小數點后是否超過了3位-惡意輸入
this.ruleForm.price = value.substring(0, value.lastIndexOf('.') + 5);
return;
}
if (/^0\d*(\.\d{0,4})?$/.test(value)) { // 匹配第一位是否是0開始
this.ruleForm.price = value.replace(/^([0][0]*)/, '');
return;
}
this.ruleForm.price = value.substring(0, (value.length - 1));
}
}
}