element-ui Form表单验证
element-ui Form表单验证规则全解
element的form表单非常好用,自带了验证规则,用起来很方便,官网给的案例对于一些普通场景完全没问题,不过一些复杂场景的验证还得自己多看文档摸索,自己经过数次爬坑
之后,总结了几种form表单的验证规则,为了便于阅读,验证规则是拆分的,完整的代码放在文末
1. 普通输入验证
<el-form-item label="活动名称" prop="name"> <!-- validate-event属性的作用是: 输入时不触发表单验证.提交时再验证,你也可以设置成动态验证 --> <el-input v-model="registData.name" :validate-event="false"></el-input> </el-form-item> rules: { // 表单验证规则 name: [ { required: true, message: '请输入活动名称' }, // 'blur'是鼠标失去焦点的时候会触发验证 { min: 3, max: 5, message: '长度在 3 到 5 个字符' } ] }
2. 数字类型验证
<el-form-item label="区域面积" prop="area"> <!-- 输入的类型为Number时,需要加一个数字转换的修饰符,输入框默认的类型是String类型,但是我试了一下,发现并不能做验证,所以自己写了函数方法验证 --> <!-- <el-input v-model.number="registData.area" autocomplete="off"></el-input> --> <!-- keyup是鼠标弹起事件, autocomplete是input自带的原生属性,自动补全功能,on为开启,off为关闭 --> <el-input v-model="registData.area" @keyup.native="InputNumber('area')" autocomplete="off"></el-input> </el-form-item> area: [ // 数字类型 'number', 整数: 'integer', 浮点数: 'float' // {type: 'number', message: '请输入数字类型', trigger: 'blur'}, // {type: 'integer', message: '请输入数字类型', trigger: 'change'}, // 'change'是表单的值改变的时候会触发验证 {required: true, message: '请输入区域面积', trigger: 'blur'} ], // 自己写的正则验证,限制用户输入数字以外的字符 // 过滤输入的金额 InputNumber (property) { this.registData[property] = this.limitInputPointNumber(this.registData[property]) }, // 验证只能输入数字 limitInputNumber (val) { if (val) { return String(val).replace(/\D/g, '') } return val }, // 限制只能输入数字(可以输入两位小数) limitInputPointNumber (val) { if (val === 0 || val === '0' || val === '') { return '' } else { let value = null value = String(val).replace(/[^\d.]/g, '') // 清除“数字”和“.”以外的字符 value = value.replace(/\.{2,}/g, '.') // 只保留第一个. 清除多余的 value = value.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.') value = value.replace(/^(-)*(\d+)\.(\d\d).*$/, '$1$2.$3') // 只能输入两个小数 return Number(value) } },
3.1 嵌套验证(独立验证)
这种情况是一行里有多个输入框或选择的情况,这里有两种方法,第一种是el-form嵌套写法,验证是独立的
<el-form-item label="活动时间" required> <el-col :span="11"> <el-form-item prop="date1"> <el-date-picker type="date" placeholder="选择日期" v-model="registData.date1" style="width: 100%;"></el-date-picker> </el-form-item> </el-col> <el-col class="line" :span="2">-</el-col> <el-col :span="11"> <el-form-item prop="date2"> <el-time-picker type="fixed-time" placeholder="选择时间" v-model="registData.date2" style="width: 100%;"></el-time-picker> </el-form-item> </el-col> </el-form-item> date1: [ { type: 'date', required: true, message: '请选择日期', trigger: 'change' } ], date2: [ { type: 'date', required: true, message: '请选择时间', trigger: 'change' } ],
3.2 嵌套验证(联动验证)
这种是联动验证,适用省级联动场景,先选国家后触发城市验证
<!-- region是一个对象,国家和城市是它的属性 --> <el-form-item label="活动区域" prop="region"> <el-select v-model="registData.region.country" placeholder="请选择国家"> <el-option label="国家一" value="USA"></el-option> <el-option label="国家二" value="China"></el-option> </el-select> <el-select v-model="registData.region.city" placeholder="请选择城市"> <el-option label="城市一" value="shanghai"></el-option> <el-option label="城市二" value="beijing"></el-option> </el-select> </el-form-item> region: [ { type: 'object', required: true, // 这里有两种处理,一种是自定义验证,拿到值后自己对属性进行验证,比较麻烦 // validator: (rule, value, callback) => { // console.log(55, value) // if (!value.country) { // callback(new Error('请选择国家')) // } else if (!value.city) { // callback(new Error('请选择城市')) // } else { // callback() // } // }, trigger: 'change', // 官网提供了对象的嵌套验证,只需要把需要验证的属性,放在fields对象里,就会按顺序进行验证 fields: { country: {required: true, message: '请选择国家', trigger: 'blur'}, city: {required: true, message: '请选择城市', trigger: 'blur'} } } ],
4. 图片上传验证(手动触发部分验证方法)
有时候会需要在表单里上传图片,但是图片上传是一个异步过程,属性值改变后不会去触发验证规则
<el-form-item label="活动图片" prop="fileUrl"> <el-upload :action="action" :on-success="handleSuccess" :data="uploadData" :limit="20" list-type="picture-card" :on-preview="handlePreview" :on-remove="handleRemove"> <i class="el-icon-plus"></i> </el-upload> </el-form-item> fileUrl: [ { required: true, message: '请上传图片', trigger: 'change' } ], // 删除图片 handleRemove (file, fileList) { this.registData.fileUrl = '' // 文件删除后也要触发验证,validateField是触发部分验证的方法,参数是prop设置的值 this.$refs.registerRef.validateField('fileUrl') }, // 图片上传 handleSuccess (res, file, fileList) { // 这里可以写文件上传成功后的处理,但是一定要记得给fileUrl赋值 this.registData.fileUrl = 'fileUrl' // 文件上传后不会触发form表单的验证,要手动添加验证 this.$refs.registerRef.validateField('fileUrl') },
完整的代码
<template> <div> <p>shopInfo</p> <div class="company" id="company"> <!-- model是验证的数据来源 --> <el-form :model="registData" :rules="rules" ref="registerRef" label-width="100px" class="demo-ruleForm"> <el-form-item label="活动名称" prop="name"> <!-- validate-event输入时不触发表单验证,提交时再验证,也可以设置成动态验证 --> <el-input v-model="registData.name" :validate-event="false"></el-input> </el-form-item> <el-form-item label="区域面积" prop="area"> <!-- 输入的类型为Number时,需要加一个数字转换的修饰符,输入框默认的类型是String类型,但是我试了一下,发现并不能做验证,所以自己写了函数方法验证 --> <!-- <el-input v-model.number="registData.area" autocomplete="off"></el-input> --> <el-input v-model="registData.area" @keyup.native="InputNumber('area')" autocomplete="off"></el-input> </el-form-item> <el-form-item label="活动区域" prop="region"> <el-select v-model="registData.region.country" placeholder="请选择国家"> <el-option label="国家一" value="USA"></el-option> <el-option label="国家二" value="China"></el-option> </el-select> <el-select v-model="registData.region.city" placeholder="请选择城市"> <el-option label="城市一" value="shanghai"></el-option> <el-option label="城市二" value="beijing"></el-option> </el-select> </el-form-item> <el-form-item label="活动时间" required> <el-col :span="11"> <el-form-item prop="date1"> <el-date-picker type="date" placeholder="选择日期" v-model="registData.date1" style="width: 100%;"></el-date-picker> </el-form-item> </el-col> <el-col class="line" :span="2">-</el-col> <el-col :span="11"> <el-form-item prop="date2"> <el-time-picker type="fixed-time" placeholder="选择时间" v-model="registData.date2" style="width: 100%;"></el-time-picker> </el-form-item> </el-col> </el-form-item> <el-form-item label="即时配送" prop="delivery"> <el-switch v-model="registData.delivery"></el-switch> </el-form-item> <el-form-item label="活动性质" prop="type"> <el-checkbox-group v-model="registData.type"> <el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox> <el-checkbox label="地推活动" name="type"></el-checkbox> <el-checkbox label="线下主题活动" name="type"></el-checkbox> <el-checkbox label="单纯品牌曝光" name="type"></el-checkbox> </el-checkbox-group> </el-form-item> <el-form-item label="特殊资源" prop="resource"> <el-radio-group v-model="registData.resource"> <el-radio label="线上品牌商赞助"></el-radio> <el-radio label="线下场地免费"></el-radio> </el-radio-group> </el-form-item> <el-form-item label="活动图片" prop="fileUrl"> <el-upload :action="action" :on-success="handleSuccess" :data="uploadData" :limit="20" list-type="picture-card" :on-preview="handlePreview" :on-remove="handleRemove"> <i class="el-icon-plus"></i> </el-upload> </el-form-item> <el-form-item label="活动形式" prop="desc"> <el-input type="textarea" v-model="registData.desc"></el-input> </el-form-item> <el-form-item> <!-- 提交的时候传入的是表单的ref --> <el-button type="primary" @click="submitForm('registerRef')">立即创建</el-button> <el-button @click="resetForm('registerRef')">重置</el-button> </el-form-item> </el-form> </div> </div> </template> <style scoped> .company { padding: 30px; text-align: left; width: 600px; } </style> <script> export default { name: 'shopInfo', data () { return { registData: { name: '', // 名称 area: '', // 面积 region: {}, // 地区 date1: '', // 日期 date2: '', // 时间 delivery: false, // 即时配送 type: [], // 活动性质 resource: '', // 特殊资源 fileUrl: '', // 活动图片 desc: '' // 活动形式 }, // 需要验证的表单属性,必须在data中定义 rules: { // 表单验证规则 name: [ { required: true, message: '请输入活动名称' }, // 'blur'是鼠标失去焦点的时候会触发验证 { min: 3, max: 5, message: '长度在 3 到 5 个字符' } ], area: [ // 数字类型 // {type: 'number', message: '请输入数字类型', trigger: 'blur'}, // {type: 'integer', message: '请输入数字类型', trigger: 'change'}, // 'change'是表单的值改变的时候会触发验证 {required: true, message: '请输入区域面积', trigger: 'blur'} ], region: [ { type: 'object', required: true, // validator: (rule, value, callback) => { // console.log(55, value) // if (!value.country) { // callback(new Error('请选择国家')) // } else if (!value.city) { // callback(new Error('请选择城市')) // } else { // callback() // } // }, trigger: 'change', fields: { country: {required: true, message: '请选择国家', trigger: 'blur'}, city: {required: true, message: '请选择城市', trigger: 'blur'} } } ], 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' } ], fileUrl: [ { required: true, message: '请上传图片', trigger: 'change' } ], desc: [ { required: true, message: '请填写活动形式', trigger: 'blur' } ] }, action: `https://jsonplaceholder.typicode.com/posts/`, uploadData: {userId: 1304, pathName: 'company'} } }, created () { }, methods: { // 过滤输入的金额 InputNumber (property) { this.registData[property] = this.limitInputPointNumber(this.registData[property]) }, // 验证只能输入数字 limitInputNumber (val) { if (val) { return String(val).replace(/\D/g, '') } return val }, // 限制只能输入数字(可以输入两位小数) limitInputPointNumber (val) { if (val === 0 || val === '0' || val === '') { return '' } else { let value = null value = String(val).replace(/[^\d.]/g, '') // 清除“数字”和“.”以外的字符 value = value.replace(/\.{2,}/g, '.') // 只保留第一个. 清除多余的 value = value.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.') value = value.replace(/^(-)*(\d+)\.(\d\d).*$/, '$1$2.$3') // 只能输入两个小数 return Number(value) } }, // 预览图片 handlePreview (file) { }, // 删除图片 handleRemove (file, fileList) { this.registData.fileUrl = '' // 文件删除后也要触发验证,validateField是触发部分验证的方法,参数是prop设置的值 this.$refs.registerRef.validateField('fileUrl') }, // 图片上传 handleSuccess (res, file, fileList) { // 这里可以写文件上传成功后的处理,但是一定要记得给fileUrl赋值 this.registData.fileUrl = 'fileUrl' // 文件上传后不会触发form表单的验证,要手动添加验证 this.$refs.registerRef.validateField('fileUrl') }, submitForm (formName) { console.log(this.registData) this.$refs[formName].validate((valid) => { if (valid) { alert('submit!') } else { console.log('error submit!!') return false } }) }, resetForm (formName) { this.$refs[formName].resetFields() } } }
再补充两个错误显示的方法
有时候我们的数据在修改页面中,赋值为空会触发验证错误,这种在一个prop控制多个form-item时会出现.这时候希望页面加载时不验证,在特定时候验证,可以使用error这个属性
error初始值为空时不会展示错误信息,一旦有值就会在页面展示错误信息
<el-form-item class="region" label="" :error="nameError"> <el-input v-model="registData.name" @change="changeName" :validate-event="false"></el-input> </el-form-item> methods: { data: { return () { nameError: '' } } changeName () { // 设置了单独的error时,不会触发el-form的验证,它只根据error是否有值来展示错误 if (this.registData.name) { this.nameError = '' } else { this.nameError = '请输入名称' } } }
另一种场景: 自定义错误样式
el-form的错误信息默认是在输入框底部一行展示,如果需要特地的样式,可以使用slot
<el-form-item label="" prop="password">
<el-input v-model="perfectInfo.password" :placeholder="pwdPlaceholder" :maxlength="24" auto-complete="new-password" >
</el-input>
<template slot="error" slot-scope="slot">
<div class="el-form_tip tt">
<div class="item_tip">{{pwdFormatTips1}}</div>
<div class="item_tip">{{pwdFormatTips2}}</div>
<div class="item_tip">{{pwdFormatTips3}}</div>
<div class="item_tip">{{pwdFormatTips4}}</div>
</div>
</template>
</el-form-item>