表单校验
直接上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| <template> <div class="container"> <el-form ref="ruleForm" :rules="rules" :model="form" inline class="form-style" > <el-form-item label="企业性质" prop="natureEnterprise"> <el-select v-model="form.natureEnterprise"> <el-option label="国企" :value="1" /> <el-option label="事业单位" :value="2" /> <el-option label="个体户" :value="3" /> </el-select> </el-form-item> <el-form-item label="业务类型" prop="type"> <el-select v-model="form.type"> <el-option label="护肤" :value="1" /> <el-option label="食品" :value="2" /> </el-select> </el-form-item> <el-form-item label="企业名称" prop="name"> <el-input v-model="form.name" placeholder="请输入" /> </el-form-item> <el-form-item label="社会统一信用代码" prop="creditCode"> <el-input v-model="form.creditCode" placeholder="请输入" /> </el-form-item> <el-form-item label="注册地址" prop="address"> <el-input v-model="form.address" placeholder="请输入" /> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm('ruleForm')" >立即创建</el-button> <el-button @click="resetForm('ruleForm')">重置</el-button> </el-form-item> </el-form> </div> </template>
<script> export default { data() { return { form: { natureEnterprise: null, type: null, address: '', name: '', creditCode: '' }, rules: { natureEnterprise: [ { required: true, message: '企业性质不能为空', trigger: 'change' } ], type: [ { required: true, message: '业务类型不能为空', trigger: 'change' } ], address: [ { required: true, message: '注册地址不能为空', trigger: 'change' } ], name: [ { required: true, message: '企业名称不能为空', trigger: 'change' } ], creditCode: [ { required: true, message: '社会统一信用代码不能为空', trigger: 'change' } ] } } }, methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { alert('submit!') } else { console.log('error submit!!') return false } }) }, resetForm(formName) { this.$refs[formName].resetFields() } } } </script>
<style lang="scss" scoped> .container { padding: 30px; .form-style { display: flex; flex-direction: column; } } </style>
|
全部校验:
以上表单为例,要求默认全部必填,如果企业性质为 个体户
,则 注册地址
和 社会统一信用代码
为 非必填
,让我们增加以下代码来实现这个需求:
1 2 3 4 5 6 7
| watch: { 'form.natureEnterprise'(val) { this.$refs['ruleForm'].clearValidate() this.rules.creditCode[0].required = val !== 3 this.rules.address[0].required = val !== 3 } }
|
通过手动修改 rules
中的 required
值来动态判断某些字段是否必填:
如果此时 新增一个校验
,假设要求业务类型为护肤时,企业名称非必填,那我们需要像上面监听业务类型的值然后做相应的判断,随着表单内容的增多,我们的 watch
会越来越多,同时 rules
也会散落在不同的地方,这必然会为后续的代码维护带来困难,接手的人也必须小心翼翼的在上面做修改。
使用computed进行表单校验优化
将 rules
作为计算属性里的值统一处理,而不是放在 data
里,避免需要频繁去操作 data
里的 rules
,也避免 rules
的项散落在页面各处。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| computed: { rules({ form }) { const isSelfEmploy = form.natureEnterprise === 3 return { natureEnterprise: [ { required: true, message: '企业性质不能为空', trigger: 'change' } ], type: [ { required: true, message: '业务类型不能为空', trigger: 'change' } ], name: [ { required: true, message: '企业名称不能为空', trigger: 'change' } ], address: [ { required: !isSelfEmploy, message: '注册地址不能为空', trigger: 'change' } ], creditCode: [ { required: !isSelfEmploy, message: '社会统一信用代码不能为空', trigger: 'change' } ] } } },
|
改用 computed
后,会有一个问题:页面初始加载或 computed
里使用的相关值改变时会 立即触发检验
。看起来体验不是很好, el-form
有一个 validate-on-rule-change
属性,表示会在 rules
属性改变后立即触发一次验证,默认为 true
,将其设置为 false
即可。
1 2 3
| <el-form :validate-on-rule-change="false" ></el-form>
|
表单拆分
当表单内容变得庞大时,将其塞在一个文件里进行开发时无疑会变得很臃肿。这时候我们可以将其拆分成一个一个的组件,每个组件里独立负责自己的表单内容以及校验,最后提交时由父组件统一收集每个子组件的数据进行提交,这样避免了所有内容都放在一个文件里变得大而杂,同时也有利于团队多人进行开发,减少冲突。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <template> <!-- 子组件-基础信息表单 --> <base-form ref="baseFormRef" /> <!-- 子组件-合作信息表单 --> <coop-form ref="coopFormRef" /> <el-button type="primary" @click="handleSave">保存</el-button> </template>
<script> import BaseForm from './base-form' import CoopForm from './coop-form'
export default { components: { BaseForm, CoopForm }, methods: { async handleSave() { const baseFormData = await this.$refs['baseFormRef'].validate() const coopFormData = await this.$refs['coopFormRef'].validate() if (baseFormData && coopFormData) { const mainFormData = { ...baseFormData, ...coopFormData } await saveApi(mainForm) this.$message.success('保存成功!') } } } } </script>
|
子组件负责处理自己的内容,同时提供方法给父组件调用,在方法里进行校验,校验通过后再返回自身的表单数据给父组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <script> export default { data() { return { form: { } } }, computed: { rules({ form }) { return { } } }, methods: { validate() { return new Promise(resolve => { this.$refs['ruleForm'].validate(valid => { if (valid) { resolve(this.form) } else { resolve(null) } }) }) } } } </script>
|
完整参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
| <template> <div class="container"> <el-form ref="ruleForm" :rules="rules" :model="form" :validate-on-rule-change="false" inline class="form-style" > <el-form-item label="企业性质" prop="natureEnterprise"> <el-select v-model="form.natureEnterprise"> <el-option label="国企" :value="1" /> <el-option label="事业单位" :value="2" /> <el-option label="个体户" :value="3" /> </el-select> </el-form-item> <el-form-item label="业务类型" prop="type"> <el-select v-model="form.type"> <el-option label="护肤" :value="1" /> <el-option label="食品" :value="2" /> </el-select> </el-form-item> <el-form-item label="企业名称" prop="name"> <el-input v-model="form.name" placeholder="请输入" /> </el-form-item> <el-form-item label="社会统一信用代码" prop="creditCode"> <el-input v-model="form.creditCode" placeholder="请输入" /> </el-form-item> <el-form-item label="注册地址" prop="address"> <el-input v-model="form.address" placeholder="请输入" /> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm('ruleForm')" >立即创建</el-button> <el-button @click="resetForm('ruleForm')">重置</el-button> </el-form-item> </el-form> </div> </template>
<script> export default { data() { return { form: { natureEnterprise: null, type: null, address: '', name: '', creditCode: '' } } }, computed: { rules({ form }) { const isSelfEmploy = form.natureEnterprise === 3 return { natureEnterprise: [ { required: true, message: '企业性质不能为空', trigger: 'change' } ], type: [ { required: true, message: '业务类型不能为空', trigger: 'change' } ], name: [ { required: true, message: '企业名称不能为空', trigger: 'change' } ], address: [ { required: !isSelfEmploy, message: '注册地址不能为空', trigger: 'change' } ], creditCode: [ { required: !isSelfEmploy, message: '社会统一信用代码不能为空', trigger: 'change' } ] } } }, methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { alert('submit!') } else { console.log('error submit!!') return false } }) }, resetForm(formName) { this.$refs[formName].resetFields() } } } </script> <style lang="scss" scoped> .container { padding: 30px; .form-style { display: flex; flex-direction: column; } } </style>
|
参考