引言
在中后台系统的日常开发中,表单必不可少,当表单内容比较多,例如有上百个字段(这一点都不夸张,血淋淋的现实)时,代码往往也变得复杂且难以维护,加上各种动态联动的表单校验,无疑让我们的页面开发过程雪上加霜,本文将结合自己平时的开发习惯,分享一下在大表单开发中如何处理复杂的表单校验,以及如何对表单进行拆分,减少单个文件堆积过多的代码内容。
表单校验
<template>
<el-form
ref="ruleForm"
:rules="rules"
:model="form"
inline
>
<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-input>
</el-form-item>
<el-form-item label="社会统一信用代码" prop="creditCode">
<el-input v-model="form.creditCode" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="注册地址" prop="address">
<el-input v-model="form.address" placeholder="请输入"></el-input>
</el-form-item>
</el-form>
</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' }
]
}
}
}
}
</script>
以上表单为例,要求默认全部必填,如果企业性质为个体户,则注册地址和社会统一信用代码为非必填,让我们增加以下代码来实现这个需求:
watch: {
'form.natureEnterprise': {
hanlder(val) {
this.rules.creditCode[0].required = val !== 3
this.rules.address[0].required = val !== 3
}
}
}
如果此时新增一个校验,假设要求业务类型为护肤时,企业名称非必填,那我们需要像上面监听业务类型的值然后做相应的判断,随着表单内容的增多,我们的watch会越来越多,同时rules也会散落在不同的地方,这必然会为后续的代码维护带来困难,接手的人也必须小心翼翼的在上面做修改。
使用computed进行表单校验优化
将rules作为计算属性里的值统一处理,而不是放在data里,避免需要频繁去操作data里的rules,也避免rules的项散落在页面各处。
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即可
<el-form
:validate-on-rule-change="false"
></el-form>
表单拆分
当表单内容变得庞大时,将其塞在一个文件里进行开发时无疑会变得很臃肿。这时候我们可以将其拆分成一个一个的组件,每个组件里独立负责自己的表单内容以及校验,最后提交时由父组件统一收集每个子组件的数据进行提交,这样避免了所有内容都放在一个文件里变得大而杂,同时也有利于团队多人进行开发,减少冲突。
// 父组件:main-form.vue
<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>
子组件负责处理自己的内容,同时提供方法给父组件调用,在方法里进行校验,校验通过后再返回自身的表单数据给父组件。
// 子组件示例:base-form.vue
<template>
<el-form ref="ruleForm" :model="form" :rules="rules">
</el-form>
</template>
<script>
export default {
data() {
return {
form: {
// ...
},
rules: {
// ...
}
}
},
methods: {
// 提供给父组件的方法并返回表单数据
validate() {
return new Promise(resolve => {
this.$refs['ruleForm'].validate(valid => {
// 校验通过返回表单数据,反之,返回null
if (valid) {
resolve(this.form)
} else {
resolve(null)
}
})
})
}
}
}
</script>
表单兄弟组件的数据通信问题
将大表单拆分后,有些时候兄弟组件间需要通信,例如coop-form里的某个字段需要根据base-form的某个字段来决定是否必填。我通常选择使用vuex解决,在base-form的值变化时将其保存到vuex里,coop-form则可以从vuex里获取,然后进行自己的逻辑处理。
// vuex里新建文件用来存放表单通信数据
// src/store/modules/formDta.js
export default {
namespaced: true,
state: {
natureEnterprise: ''
},
mutations: {
SET_NATURE_ENTERPRISE(state, payload) {
state.natureEnterprise = payload
}
}
}
// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import formData from './modules/formData.js'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
formData
}
})
// base-form.vue
watch: {
'form.natureEnterprise': {
handler(val) {
// 将企业性质的值存储到vuex里
this.$store.commit('formData/SET_NATURE_ENTERPRISE', val)
}
}
}
// coop-form.vue
computed: {
...mapState('formData', [
'natureEnterprise'
]),
rules() {
return {
address: [
{ required: this.natureEnterprise === 1, message: '注册地址不能为空', trigger: 'change' }
]
}
}
}
以上就是vue开发中后台系统复杂表单优化技巧的详细内容,更多关于vue后台系统复杂表单优化的资料请关注编程网其它相关文章!