# 前言
工作中经常遇见一些大型表单需求,写出来的代码庞大臃肿,不利于维护,介于此种情况我的解决方案是拆分表单,大表单文件不用一个vue文件来书写,而是把它拆分成几个子表单组件。每个子表单维护自己的表单数据与校检,最后统一由父组件来组装数据,这个过程肯定会出现大量的重复性代码,因此vue2可以使用minxins混入,vue3则直接使用组合式api,思路都是一致的,vue2关键代码如下:
父组件
<template>
<div>
<sub-form1 :data="formDataMap"
formKey="SubForm1"
ref="SubForm1">
</sub-form1>
<sub-form2 :data="formDataMap"
formKey="SubForm2"
ref="SubForm2">
</sub-form2>
{{submitForm}}
<a-form-model-item :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary"
@click="onSubmit">
提交数据
</a-button>
<a-button style="margin-left: 10px;"
@click="resetFields">
清除数据
</a-button>
</a-form-model-item>
</div>
</template>
<script>
import SubForm1 from './components/subForm1.vue'
import SubForm2 from './components/subForm2.vue'
export default {
components: {
SubForm1,
SubForm2,
},
data() {
return {
formDataMap: {
SubForm1: {
name1: '',
region1: undefined,
date1: undefined,
delivery1: false,
type1: [],
resource1: '',
desc1: '',
},
SubForm2: {
name2: '',
region2: undefined,
date2: undefined,
delivery2: false,
type2: [],
resource2: '',
desc2: '',
},
},
submitForm: {},
}
},
methods: {
// 获取转后的表单数据
getConvertdData(refer, target) {
const that = this
const form = {}
Object.entries(refer).forEach(([key, value]) => {
if (key.startsWith('Sub')) {
// 这里相当于做了一个约定,只要以Sub开头就代表数据还需要继续转换
form[key] = that.getConvertdData(value, target)
} else {
form[key] = target[key]
}
})
return form
},
// 获取子表单组件的ref取值
getFormRefName() {
return Object.keys(this.formDataMap)
},
// 组装子表单数据并汇总
getFormData() {
return this.getFormRefName()
.map((key) => {
return this.$refs[key].getFormData()
})
.reduce((total, cur) => Object.assign(total, cur), {})
},
// 验证各子表单数据
validate() {
return this.getFormRefName().map(async (key) => {
return await this.$refs[key].validate()
})
},
resetFields() {
this.getFormRefName().forEach((key) => {
this.$refs[key].resetFields()
})
},
onSubmit() {
this.submitForm = this.getFormData()
},
},
}
</script>
<style></style>
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
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
子组件1
<template>
<a-card title="子表单1">
<a-form-model :model="formData"
:label-col="labelCol"
:wrapper-col="wrapperCol"
ref="form">
<a-form-model-item label="Activity name"
prop="name1">
<a-input v-model="formData.name1" />
</a-form-model-item>
<a-form-model-item label="Activity zone"
prop="region1">
<a-select v-model="formData.region1"
placeholder="please select your zone">
<a-select-option value="shanghai">
Zone one
</a-select-option>
<a-select-option value="beijing">
Zone two
</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="Activity time"
prop="date1">
<a-date-picker v-model="formData.date1"
show-time
type="date"
placeholder="Pick a date"
style="width: 100%;" />
</a-form-model-item>
<a-form-model-item label="Instant delivery"
prop="delivery1">
<a-switch v-model="formData.delivery1" />
</a-form-model-item>
<a-form-model-item label="Activity type"
prop="type1">
<a-checkbox-group v-model="formData.type1">
<a-checkbox value="1"
name="type">
Online
</a-checkbox>
<a-checkbox value="2"
name="type">
Promotion
</a-checkbox>
<a-checkbox value="3"
name="type">
Offline
</a-checkbox>
</a-checkbox-group>
</a-form-model-item>
<a-form-model-item label="Resources"
prop="resource1">
<a-radio-group v-model="formData.resource1">
<a-radio value="1">
Sponsor
</a-radio>
<a-radio value="2">
Venue
</a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item label="Activity form"
prop="desc1">
<a-input v-model="formData.desc1"
type="textarea" />
</a-form-model-item>
</a-form-model>
{{formData}}
</a-card>
</template>
<script>
import formMinxin from '../mixins/formMinxin'
export default {
mixins: [formMinxin],
}
</script>
<style>
</style>
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
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
子组件2
<template>
<a-card title="子表单2">
<a-form-model :model="formData"
:label-col="labelCol"
:wrapper-col="wrapperCol"
ref="form">
<a-form-model-item label="Activity name"
prop="name2">
<a-input v-model="formData.name2" />
</a-form-model-item>
<a-form-model-item label="Activity zone"
prop="region2">
<a-select v-model="formData.region2"
placeholder="please select your zone">
<a-select-option value="shanghai">
Zone one
</a-select-option>
<a-select-option value="beijing">
Zone two
</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item label="Activity time"
prop="date2">
<a-date-picker v-model="formData.date2"
show-time
type="date"
placeholder="Pick a date"
style="width: 100%;" />
</a-form-model-item>
<a-form-model-item label="Instant delivery"
prop="delivery2">
<a-switch v-model="formData.delivery2" />
</a-form-model-item>
<a-form-model-item label="Activity type"
prop="type2">
<a-checkbox-group v-model="formData.type2">
<a-checkbox value="1"
name="type">
Online
</a-checkbox>
<a-checkbox value="2"
name="type">
Promotion
</a-checkbox>
<a-checkbox value="3"
name="type">
Offline
</a-checkbox>
</a-checkbox-group>
</a-form-model-item>
<a-form-model-item label="Resources"
prop="resource2">
<a-radio-group v-model="formData.resource2">
<a-radio value="1">
Sponsor
</a-radio>
<a-radio value="2">
Venue
</a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item label="Activity form"
prop="desc2">
<a-input v-model="formData.desc2"
type="textarea" />
</a-form-model-item>
</a-form-model>
{{formData}}
</a-card>
</template>
<script>
import formMinxin from '../mixins/formMinxin'
export default {
mixins: [formMinxin],
}
</script>
<style>
</style>
<style>
</style>
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
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
混入文件
import { cloneDeep } from "lodash"
export default {
props: {
// 父表单传过来的值
data: {
type: Object,
default() {
return {}
}
},
// 表单标识
formKey: {
type: String,
default: ''
}
},
data() {
return {
formData: {},
labelCol: { span: 4 },
wrapperCol: { span: 14 },
}
},
computed: {
parentFormData() {
return this.data[this.formKey]
}
},
watch: {
parentFormData: {
handler(val) {
this.formData = cloneDeep(val)
},
immediate: true
}
},
methods: {
getFormData() {
return this.formData;
},
validata() {
return this.$refs.form.validata();
},
resetFields() {
this.$refs.form.resetFields();
}
},
}
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
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