Element表单校验
作为一个后端开发,总结一下实际工作中表单校验的场景和用法。
Element官网:https://element.eleme.cn/#/zh-CN/component/form
代码地址:https://gitee.com/kkmy/kw-microservices/tree/master/kw-ui/kwsphere
常用表单校验场景
- 表单基本校验(长度、非空、数字类型、金额类型)
- 嵌套对象校验 (字段较多,存在嵌套对象,使用同一个el-form)
- 字段联动校验 (审核场景,同意则审核意见置为非必输)
- 自定义校验函数 (金额类型的长度校验,身份满18岁校验)
- 重置表单、校验指定表单、校验指定字段(element表单常用方法)
- 动态列表表单(添加多条配置)
- 文件校验 (element上传组件)
- 多表单el-form提交校验
场景使用Demo
表单基本校验
html
<template>
<div class="container">
<div class="center-container">
<el-form :model="userForm" :rules="rules" ref="userForm" label-width="100px"
class="demo-userForm">
<el-form-item label="姓名" prop="name">
<el-input v-model="userForm.name"></el-input>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="userForm.gender">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
</el-radio-group>
</el-form-item>
<!--中国行政区划代码:https://www.mca.gov.cn/n156/n186/c110746/content.html-->
<el-form-item label="籍贯" prop="nativePlace">
<el-select v-model="userForm.nativePlace" placeholder="请选择性别">
<el-option value="110000" label="北京市"></el-option>
<el-option value="120000" label="天津市"></el-option>
</el-select>
</el-form-item>
<el-form-item label="管理员" prop="admin">
<el-switch v-model="userForm.admin"></el-switch>
</el-form-item>
<el-form-item label="爱好" prop="hobby">
<el-checkbox-group v-model="userForm.hobby">
<el-checkbox label="骑行" name="hobby"></el-checkbox>
<el-checkbox label="跑步" name="hobby"></el-checkbox>
<el-checkbox label="网游" name="hobby"></el-checkbox>
<el-checkbox label="旅行" name="hobby"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="个性签名" prop="desc">
<el-input type="textarea" v-model="userForm.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('userForm')">保 存</el-button>
<el-button @click="resetForm('userForm')">重 置</el-button>
</el-form-item>
</el-form>
</div>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
@close="closeDialog"
:close-on-click-modal="false"
:close-on-press-escape="false"
center>
<span><pre>{{userForm}}</pre></span>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="centerDialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "validate-01",
data() {
return {
userForm: {
name: '',
nativePlace: '',
admin: false,
hobby: [],
gender: '',
desc: ''
},
rules: {
name: [
{required: true, message: '请输入姓名', trigger: ['blur', 'change']},
{min: 2, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur'}
],
nativePlace: [
{required: true, message: '请选择籍贯', trigger: 'blur'}
],
hobby: [
{type: 'array', required: true, message: '请至少选择一个爱好', trigger: 'change'},
{type: 'array', min: 2, message: '请至少选择2个爱好', trigger: 'change'},
],
gender: [
{required: true, message: '请选择性别', trigger: 'change'}
],
desc: [
{required: true, message: '请填写个性签名', trigger: 'blur'},
{max: 200, message: '个性签名长度不能大于200', trigger: 'blur'},
]
},
centerDialogVisible: false,
};
},
methods: {
closeDialog() {
this.centerDialogVisible = false;
this.$refs.userForm.resetFields();
},
submitForm(formName) {
this.$refs.userForm.validate((valid) => {
if (valid) {
this.centerDialogVisible = true;
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
//this.$refs[formName].resetFields();
this.$refs.userForm.resetFields();
}
}
}
</script>
<style scoped>
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置父容器的高度为视口高度,使其充满整个屏幕 */
}
.center-container {
max-width: 600px; /* 设置内部容器的最大宽度,根据需求进行调整 */
}
</style>
嵌套对象校验
html
<template>
<div class="container">
<div class="center-container">
<el-form :model="userForm" :rules="rules" ref="userForm" label-width="100px"
class="demo-userForm">
<span>基本信息:</span>
<br>
<el-form-item label="姓名" prop="name">
<el-input v-model="userForm.name"></el-input>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="userForm.gender">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="籍贯" prop="nativePlace">
<el-select v-model="userForm.nativePlace" placeholder="请选择性别">
<el-option value="110000" label="北京市"></el-option>
<el-option value="120000" label="天津市"></el-option>
</el-select>
</el-form-item>
<span>联系方式:</span>
<br>
<el-form-item label="QQ" prop="contactDetails.qq">
<el-input v-model="userForm.contactDetails.qq"></el-input>
</el-form-item>
<el-form-item label="微信" prop="contactDetails.wx">
<el-input v-model="userForm.contactDetails.wx"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="contactDetails.phone">
<el-input v-model="userForm.contactDetails.phone"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('userForm')">保 存</el-button>
<el-button @click="resetForm('userForm')">重 置</el-button>
</el-form-item>
</el-form>
</div>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
@close="closeDialog"
:close-on-click-modal="false"
:close-on-press-escape="false"
center>
<span><pre>{{ userForm }}</pre></span>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="centerDialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "validate-01",
data() {
return {
userForm: {
name: '',
nativePlace: '',
gender: '',
contactDetails: {
qq: '',
wx: '',
phone: ''
}
},
rules: {
name: [
{required: true, message: '请输入姓名', trigger: ['blur', 'change']},
{min: 2, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur'}
],
nativePlace: [
{required: true, message: '请选择籍贯', trigger: 'blur'}
],
gender: [
{required: true, message: '请选择籍贯', trigger: 'change'}
],
'contactDetails.qq': [
{required: true, message: '请输入联系方式qq', trigger: ['blur', 'change']},
],
'contactDetails.wx': [
{required: true, message: '请输入联系方式微信', trigger: ['blur', 'change']},
],
'contactDetails.phone': [
{required: true, message: '请输入联系方式手机号', trigger: ['blur', 'change']},
],
},
centerDialogVisible: false,
};
},
methods: {
closeDialog() {
this.centerDialogVisible = false;
this.$refs.userForm.resetFields();
},
submitForm(formName) {
this.$refs.userForm.validate((valid) => {
if (valid) {
this.centerDialogVisible = true;
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
//this.$refs[formName].resetFields();
this.$refs.userForm.resetFields();
}
}
}
</script>
<style scoped>
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置父容器的高度为视口高度,使其充满整个屏幕 */
}
.center-container {
max-width: 600px; /* 设置内部容器的最大宽度,根据需求进行调整 */
}
</style>
字段联动校验
html
<template>
<div class="container">
<div class="center-container">
<el-form :model="userForm" :rules="rules" ref="userForm" label-width="100px"
class="demo-userForm">
<el-form-item label="审核结果" prop="result">
<el-radio-group v-model="userForm.result" @change="clearValidate">
<el-radio-button label="1">通过</el-radio-button>
<el-radio-button label="0">不通过</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="审核意见" prop="desc"
:rules=
"[
{required: userForm.result!=1, message: '请填写审核意见', trigger: 'blur'},
{max: 200, message: '审核意见长度不能大于200', trigger: 'blur'}
]">
<el-input type="textarea" v-model="userForm.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('userForm')">保 存</el-button>
<el-button @click="resetForm('userForm')">重 置</el-button>
</el-form-item>
</el-form>
</div>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
@close="closeDialog"
:close-on-click-modal="false"
:close-on-press-escape="false"
center>
<span><pre>{{ userForm }}</pre></span>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="centerDialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "validate-01",
data() {
return {
userForm: {
result: '1',
desc: ''
},
rules: {
result: [
{required: true, message: '请选择审核结果', trigger: 'change'}
],
},
centerDialogVisible: false,
};
},
methods: {
closeDialog() {
this.centerDialogVisible = false;
this.$refs.userForm.resetFields();
},
clearValidate(val) {
if (val == 1) {
this.$refs.userForm.clearValidate('desc')
}
},
submitForm(formName) {
this.$refs.userForm.validate((valid) => {
if (valid) {
this.centerDialogVisible = true;
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
//this.$refs[formName].resetFields();
this.$refs.userForm.resetFields();
}
}
}
</script>
<style scoped>
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置父容器的高度为视口高度,使其充满整个屏幕 */
}
.center-container {
max-width: 600px; /* 设置内部容器的最大宽度,根据需求进行调整 */
}
</style>
自定义校验函数
html
<template>
<div class="container">
<div class="center-container">
<el-form :model="userForm" :rules="rules" ref="userForm" label-width="100px"
class="demo-userForm">
<el-form-item label="提现金额" prop="amt">
<el-input v-model="userForm.amt"></el-input>
</el-form-item>
<el-form-item label="证件类型" prop="idCardType">
<el-select v-model="userForm.idCardType" placeholder="请选择证件类型">
<el-option value="1" label="居民身份证"></el-option>
<el-option value="2" label="护照"></el-option>
</el-select>
</el-form-item>
<el-form-item label="证件号" prop="idCard">
<el-input v-model="userForm.idCard"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('userForm')">保 存</el-button>
<el-button @click="resetForm('userForm')">重 置</el-button>
</el-form-item>
</el-form>
</div>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
@close="closeDialog"
:close-on-click-modal="false"
:close-on-press-escape="false"
center>
<span><pre>{{ userForm }}</pre></span>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="centerDialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import {cardid} from "@/utils/validate";
export default {
name: "validate-01",
data() {
let checkAmt = (rule, value, callback) => {
if (value === '' || value === null) {
callback(new Error('请输入提现金额'));
} else if (value > 9999999.99) {
//金额总长度不能大于10,包含小数点 value.toString().length > 10
//数据库存储的类型为decimal(10,2),所以值不能大于9999999.99
callback(new Error('提现金额不能大于9999999.99'));
} else {
callback();
}
}
let checkIdCard = (rule, value, callback) => {
if (!this.userForm.idCardType) {
this.$refs.userForm.validateField('idCardType');
} else {
let idCardType = this.userForm.idCardType;
if (idCardType == 1) {
//居民身份证
console.log(cardid(value))
if (!cardid(value)[0]) {
//todo 校验未成年
callback();
} else {
callback(new Error(cardid(value)[1]))
}
} else if (idCardType == 2) {
//护照
let pattern = /^[a-zA-Z0-9]{3,20}$/;
if (!pattern.test(value)) {
callback(new Error("护照格式错误"))
}
} else {
callback();
}
}
}
return {
userForm: {
idCard: '',
idCardType: '',
amt: '',
},
rules: {
amt: [
{required: true, message: '请输入提现金额', trigger: ['blur', 'change']},
{pattern: /^\d+(\.\d{1,2})?$/, message: '金额格式错误', trigger: ['blur', 'change']},
{validator: checkAmt, trigger: ['blur', 'change']}
],
idCardType: [
{required: true, message: '请选择证件类型', trigger: ['blur']},
],
idCard: [
{required: true, message: '请输入证件号', trigger: ['blur', 'change']},
{validator: checkIdCard, trigger: ['blur', 'change']}
],
},
centerDialogVisible: false,
};
},
methods: {
closeDialog() {
this.centerDialogVisible = false;
this.$refs.userForm.resetFields();
},
submitForm(formName) {
this.$refs.userForm.validate((valid) => {
if (valid) {
this.centerDialogVisible = true;
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
//this.$refs[formName].resetFields();
this.$refs.userForm.resetFields();
}
}
}
</script>
<style scoped>
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置父容器的高度为视口高度,使其充满整个屏幕 */
}
.center-container {
max-width: 600px; /* 设置内部容器的最大宽度,根据需求进行调整 */
}
</style>
动态列表表单
html
<template>
<div class="container">
<div class="center-container">
<el-form :model="{'contractData':contractData}" ref="contForm">
<el-table :data="contractData" border style="width: 100%;" stripe>
<el-table-column label="序号" min-width="5%">
<template slot-scope="scope">
<p class="text-align:center;">{{ scope.$index + 1 }}</p>
</template>
</el-table-column>
<el-table-column prop="contName" label="合同名称" min-width="20%">
<template slot-scope="scope">
<el-form-item :prop="'contractData.'+scope.$index+'.contName'"
:rules="contRule.contName">
<el-input
v-model.trim="scope.row.contName"
placeholder="请输入合同名称" maxlength="200"
></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="合同编号" min-width="20%">
<template slot-scope="scope">
<el-form-item :prop="'contractData.'+scope.$index+'.contCode'"
:rules="contRule.contCode">
<el-input
v-model.trim="scope.row.contCode" maxlength="200"
placeholder="合同编号"
></el-input>
</el-form-item>
</template>
</el-table-column>
</el-table>
<el-form-item>
<p>
<el-button @click="addCont()">添 加</el-button>
<el-button type="primary" @click="submitForm()">保 存</el-button>
<el-button @click="resetForm()">重 置</el-button>
</p>
</el-form-item>
</el-form>
</div>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
@close="closeDialog"
:close-on-click-modal="false"
:close-on-press-escape="false"
center>
<span><pre>{{ contractData }}</pre></span>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="centerDialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "validate-01",
data() {
return {
contractData: [],
contRule: {
contCode: [
{
required: true,
message: '合同编号不能为空',
trigger: 'change'
}
],
contAmt: [
{required: true, message: '合同金额不能为空', trigger: 'change'},
{
pattern: /^(0\.0*[1-9]+[0-9]*$|[1-9]+[0-9]*\.[0-9]*[0-9]$|[1-9]+[0-9]*$)/,
message: '非法数字'
},
{
pattern: /^(([1-9]\d*)|\d)(\.\d{1,2})?$/,
message: '最多两位小数'
},
],
contName: [
{
required: true,
message: '请输入合同名称',
trigger: 'change'
}
],
},
centerDialogVisible: false,
};
},
methods: {
closeDialog() {
this.centerDialogVisible = false;
this.$refs.contForm.resetFields();
},
submitForm() {
this.$refs.contForm.validate((valid) => {
if (valid) {
if (this.contractData.length === 0) {
this.$message({
showClose: true,
message: '请先添加合同',
type: 'warning',
duration: 1500
});
} else {
this.centerDialogVisible = true;
}
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm() {
//this.$refs[formName].resetFields();
this.$refs.contForm.resetFields();
},
addCont() {
this.contractData.push({
contName: '',
contCode: ''
});
}
}
}
</script>
<style scoped>
</style>
文件校验
html
<template>
<div class="container">
<div class="center-container">
<el-form :model="userForm" :rules="rules" ref="userForm" label-width="100px"
class="demo-userForm">
<el-form-item label='附件' prop='fileList'>
<el-upload class='m-upload'
action='/mock/user/img/upload'
:headers='headers'
accept='.jpg,.png,.jpeg'
:on-success='handleAvatarSuccess'
:file-list='userForm.fileList'
:limit='2'
:on-exceed='handleExceed'
:on-preview='handlePreview'
:on-remove='handleRemove'
:before-upload="beforeAvatarUpload"
:before-remove="beforeRemove"
>
<el-button type='primary'>上传</el-button>
</el-upload>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('userForm')">保 存</el-button>
<el-button @click="resetForm('userForm')">重 置</el-button>
</el-form-item>
</el-form>
</div>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
@close="closeDialog"
:close-on-click-modal="false"
:close-on-press-escape="false"
center>
<span><pre>{{ userForm }}</pre></span>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="centerDialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import VueCookies from 'vue-cookies';
export default {
name: "validate-01",
data() {
return {
userForm: {
fileList: []
},
rules: {
fileList: [
{type: 'array', required: true, message: '请上传附件', trigger: ['change', 'blur']},
{type: 'array', min: 2, message: '请至少上传2个附件', trigger: 'change'},
],
},
centerDialogVisible: false,
};
},
computed: {
headers() {
return {
'Authorization': 'Bearer ' + VueCookies.get('access_token') // 直接从本地获取token就行
};
},
},
methods: {
closeDialog() {
this.centerDialogVisible = false;
this.$refs.userForm.resetFields();
},
submitForm() {
this.$refs.userForm.validate((valid) => {
if (valid) {
this.centerDialogVisible = true;
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm() {
this.$refs.userForm.resetFields();
},
handleAvatarSuccess(response, file, fileList) {
//上传成功
console.log("response:", JSON.stringify(response))
let self = this;
let fileInfo = {
...response.data
};
fileInfo.name = fileInfo.fileName;
self.userForm.fileList.push(fileInfo);
this.$refs.userForm.validateField("fileList")
this.$forceUpdate();
},
handleExceed(files, fileList) {
this.$message.warning('当前限制选择 2 个文件,本次选择了' + files.length + '个文件,共选择了' + (files.length + fileList.length) + ' 个文件');
},
handlePreview(val) {
console.log("val:", JSON.stringify(val))
},
handleRemove() {
this.userForm.fileList = [];
},
beforeAvatarUpload() {
},
beforeRemove() {
}
}
}
</script>
<style scoped>
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置父容器的高度为视口高度,使其充满整个屏幕 */
}
.center-container {
max-width: 600px; /* 设置内部容器的最大宽度,根据需求进行调整 */
}
</style>
多表单el-form提交校验
使用Promise语法
html
<template>
<div class="container">
<div class="center-container">
<el-form :model="userForm1" :rules="rules" ref="userForm1" label-width="100px"
class="demo-userForm">
<span>基本信息1:</span>
<el-form-item label="姓名" prop="name">
<el-input v-model="userForm1.name"></el-input>
</el-form-item>
</el-form>
<el-form :model="userForm2" :rules="rules" ref="userForm2" label-width="100px"
class="demo-userForm">
<span>基本信息2:</span>
<el-form-item label="姓名" prop="name">
<el-input v-model="userForm2.name"></el-input>
</el-form-item>
</el-form>
<el-button type="primary" @click="submitForm()">保 存</el-button>
<el-button @click="resetForm()">重 置</el-button>
</div>
<el-dialog
title="提示"
:visible.sync="centerDialogVisible"
width="30%"
@close="closeDialog"
:close-on-click-modal="false"
:close-on-press-escape="false"
center>
<span><pre>{{ userForm1 }}</pre></span>
<span><pre>{{ userForm2 }}</pre></span>
<span slot="footer" class="dialog-footer">
<el-button @click="centerDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="centerDialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "validate-01",
data() {
return {
userForm1: {},
userForm2: {},
rules: {
name: [
{required: true, message: '请输入姓名', trigger: ['blur', 'change']},
{min: 2, max: 5, message: '长度在 2 到 5 个字符', trigger: 'blur'}
],
},
centerDialogVisible: false,
};
},
methods: {
closeDialog() {
this.centerDialogVisible = false;
this.$refs.userForm1.resetFields();
this.$refs.userForm2.resetFields();
},
submitForm() {
const p1 = new Promise((resolve, reject) => {
this.$refs['userForm1'].validate(valid => {
if (valid) resolve()
})
})
const p2 = new Promise((resolve, reject) => {
this.$refs['userForm2'].validate(valid => {
if (valid) resolve()
})
})
Promise.all([p1, p2]).then(() => {
console.log('submit')
this.centerDialogVisible = true;
})
},
resetForm() {
this.$refs.userForm1.resetFields();
this.$refs.userForm2.resetFields();
}
}
}
</script>
<style scoped>
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* 设置父容器的高度为视口高度,使其充满整个屏幕 */
}
.center-container {
max-width: 600px; /* 设置内部容器的最大宽度,根据需求进行调整 */
}
</style>