系列文章:
- vue+element大规模解决方案(一)-概述
前言
从这篇文章开始,我将逐步实现评论中呈现的形状效果。通常我们在编写表单的时候,会为每个表单编写一个组件。保存时,我们使用el-form
提供的validate
方法进行验证。如果任何表单元素未能通过验证,则表单提交将被阻止;但如果表单元素足够多,那么表单文件显然会存在问题:第一,一个文件中会有大量代码,不利于后期维护;更严重的问题是几个人同时并行开发很难解决。如果多人写一个文件,很容易发生冲突,无法达到雇佣更多人缩短构建周期的目标。基于这些问题,我尝试了以下形式分解的解决方案。
综合理念
我的想法是把表单的内容分成几个子表单组件,最后将这些子表单组装在主表单组件中;提交时对子表单进行逐一检查,最终通过,收集主表单数据最终提交。
同时提交两份表格
首先,我想尝试一下如何通过点击保存按钮来提交两份电子表格。代码是:
模板部分
<el-button type="primary" @click="handleSave">保存</el-button>
<el-form ref="form1" :model="form1" :rules="rules1" label-width="80px" size="small">
<el-form-item label="姓名" prop="name">
<el-input v-model="form1.name" />
</el-form-item>
<el-form-item label="年龄">
<el-input v-model="form1.age" />
</el-form-item>
</el-form>
<el-form ref="form2" :model="form2" :rules="rules2" label-width="80px" size="small">
<el-form-item label="公司" prop="company">
<el-input v-model="form2.company" />
</el-form-item>
</el-form>
数据部分
data() {
return {
form1: {
name: '',
age: ''
},
form2: {
company: ''
},
rules1: {
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' }
]
},
rules2: {
company: [
{ required: true, message: '请输入公司', trigger: 'blur' }
]
}
}
},
如果点击“保存”,则分别检查两个表格,只有通过后才打印数据。代码是:
handleSave() {
let validResult1
let validResult2
this.$refs['form1'].validate(valid => { validResult1 = valid })
this.$refs['form2'].validate(valid => { validResult2 = valid })
if (validResult1 && validResult2) {
// 校验通过,打印表单数据
console.log(this.form1, this.form2)
} else {
this.$message.warning('校验未通过')
}
}
目前正在测试必填项未填写时的运行效果
如果所有检查都成功,则打印数据
到目前为止一切都很顺利,没有什么新鲜事。它只是验证多个表单。当所有匹配时,打印详细信息并启用提交。否则,表明检查失败。
部分板材组件扩展
既然方向可行,那么我们就开始构建子表单组件并拆分代码。这是子表单之一的代码
<template>
<el-form ref="form" :model="formData" :rules="rules" label-width="80px" size="small">
<el-form-item label="姓名" prop="name">
<el-input v-model="formData.name" />
</el-form-item>
<el-form-item label="年龄">
<el-input v-model="formData.age" />
</el-form-item>
</el-form>
</template>
js部分代码为:
export default {
name: 'Form1',
data() {
return {
formData: {},
rules: {
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' }
]
}
}
},
methods: {
validForm() {
let result = false
this.$refs['form'].validate((valid) => { result = valid })
return result
}
}
}
以同样的方式实现 form2.vue。
当前修改index.vue主表单文件
js部分
import Form1 from './form1'
import Form2 from './form2'
export default {
name: 'TheForm',
components: {
Form1,
Form2
},
data() {
return {
}
},
methods: {
handleSave() {
const validResult1 = this.$refs['form1'].validForm()
const validResult2 = this.$refs['form2'].validForm()
if (validResult1 && validResult2) {
// 校验通过,打印表单数据
console.log(this.$refs['form1'].formData)
console.log(this.$refs['form2'].formData)
} else {
this.$message.warning('校验未通过')
}
}
}
}
相比之前代码的变化是不再直接操作el-form,而是通过自定义表单组件提供的接口调用方法并获取数据(validForm
方法和formData
数据)。
测试修改后的效果为:
检查失败
检查成功,数据打印
提高可扩展性
在上面的代码中,每个表单必须定义一个validResult
变量来记录表单验证结果。显然,这是不可扩展的。由于各个子窗体的接口是一致的,所以可以无差别地使用遍历。那么如何维护遍历键值呢?另外,在上面的代码中,子表单组件无法接收用于回显的初始数据。很自然,我们使用一个formDataMap
对象来统一管理每个子页面的数据,并且我们可以使用formDataMap
的属性作为键值。 。
修改index.vue文件的data部分,添加以下代码:
formDataMap: {
form1: {
// 如果有初始值则单独罗列出来,否则空着即可
},
form2: {}
}
由于子表单组件ref
中分别使用了formDataMap
中的属性名form1
和form2
,因此在遍历时按顺序找到它们,并修改了保存功能。代码是:
handleSave() {
// 解析出全部表单key值,通过key值获取组件ref
const formKeys = Object.keys(this.formDataMap)
const validResults = formKeys.map(formKey => this.$refs[formKey].validForm())
// 如果所有校验通过
if (validResults.every(r => r)) {
// 校验通过,打印表单数据,这里不再单个输出子表单里的数据,
// 而是组装成完正的表单数据
const formData = {}
formKeys.map(formKey => {
const partFormData = this.$refs[formKey].formData
Object.assign(formData, partFormData)
})
console.log(formData)
} else {
this.$message.warning('校验未通过')
}
}
}
测试后结果如下:
检查失败
验证成功,打印数据
子表单接受初始数据
在上面的通用表单中已经定义了formDataMap
,但是没有传递到子表单中,所以我们开始传递参数
<form1 ref="form1" :data="formDataMap.form1" />
<form2 ref="form2" :data="formDataMap.form2" />
formDataMap: {
form1: {
name: 'wyh',
age: 30
},
form2: {}
}
进入 form1.vue 接受道具
props: {
data: {
type: Object,
default: () => ({})
}
},
为了在formData
中定位传入的属性,需要注意,通过使用属性immediate
,可以立即定位传入的♿
watch: {
data: {
handler(newValue) {
this.formData = easyClone(newValue) || {}
},
immediate: true
}
},
经测试一切正常。
混合提取物由于各个分页组件的逻辑类似,所以form1.vue中的很多props
、watch
和methods
应该在form2中。未来的形式。写起来当然要用mixin进行代码提取
提取的mixin代码如下:
import { easyClone } from '@/utils'
export default {
props: {
data: {
type: Object,
default: () => ({})
}
},
data() {
return {
formData: {}
}
},
watch: {
data: {
handler(newValue) {
this.formData = easyClone(newValue) || {}
},
immediate: true
}
},
methods: {
validForm() {
let result = false
this.$refs['form'].validate((valid) => { result = valid })
return result
}
}
}
解压后,form1.vue变得极其简单,只遵循规则
import SuperFormMixin from '@/mixins/super-form-mixin'
export default {
name: 'Form1',
mixins: [SuperFormMixin],
data() {
return {
rules: {
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' }
]
}
}
}
}
检查后一切正常。至此,表单划分的基本方向和实现已经出来了,接下来就是复杂表单逻辑的填充工作。下一个要面对的问题是如何实现大型形状的工具附着点?敬请期待。
感谢您的阅读,欢迎指正!
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。