introductory
At work I often need to deal with some complex, dynamic forms, but as the requirements continue to iterate, we may find that once two or three hundred lines of the.vue
The file is now unknowingly at 2,000 lines, 3,000 lines, and more...
This certainly adds a lot of difficulty to a program that needs to be maintained over a long period of time.
Therefore, in order to reduce the file size and optimize the structure of the form organization, I practiced a component-based form splitting method in my daily development, while still ensuring that all form items are in the sameel-form
Center.
This has several advantages for a project that doesn't have a well organized, componentized file to begin with:
- Minor changes! Subsequent additions of new form items will basically not change the previous code
- Component-based! Logically split form items and embed them anywhere!
- Easy to maintain! Turn a single large component into multiple widgets, with each component focusing on only a portion of the form.
Form Splitting
Next we'll cover how to practice this form organization by completing an actual form.
in order toelement-ui
Documentation for thisform (document)As an example, next try to implement it in our way
Let's start by assuming that we currently have avue
file./form/
<template>
<el-form ref="form" :model="form" label-width="140px">
...
</el-form>
<template>
<script>
export default {
name: 'myForm',
data() {
return {
form: {}
}
}
}
</script>
If we directly follow theelement-ui
form document to write, then ourThe file may look like this:
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="Name of activity">
<el-input v-model=""></el-input>
</el-form-item>
<el-form-item label="project area">
<el-select v-model="" placeholder="请选择project area">
<el-option label="Region I" value="shanghai"></el-option>
<el-option label="Region II" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="Activity time">
<el-col :span="11">
<el-date-picker type="date" placeholder="Select Date" v-model="form.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="Select Time" v-model="form.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="Instant delivery">
<el-switch v-model=""></el-switch>
</el-form-item>
<el-form-item label="Nature of activity">
<el-checkbox-group v-model="">
<el-checkbox label="gourmet food/Restaurant Online Events" name="type"></el-checkbox>
<el-checkbox label="Local marketing campaigns" name="type"></el-checkbox>
<el-checkbox label="Offline Theme Activities" name="type"></el-checkbox>
<el-checkbox label="Brand exposure alone" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="Special resources">
<el-radio-group v-model="">
<el-radio label="Online Brand Sponsorship"></el-radio>
<el-radio label="Offline venues are free"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="Forms of activity">
<el-input type="textarea" v-model=""></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">Create Now</el-button>
<el-button>abolish</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
}
},
methods: {
onSubmit() {
('submit!');
}
}
}
</script>
Suppose we also need to add an approval process to this form, such as this one in the documentationform (document)
After adding a new form item, it may look fine at the moment, but as there are more and more form items, this file will become bigger and harder to maintain. So we try to split this form item into individual components to simulate the scenario where we maintain a very large form.
New subform item component
I'm in the habit of creating, in the directory of the current form, acomponents
directory, and then in thecomponents
directory to create aaudit
directory, and in theaudit
directory to create afile for components related to the approval process. If there are subsequent components that are only
audit/
components that are only used in the file, I also put them in theaudit
Catalog. Keep the directory structure clear.
<template>
<div class="audit-form-item">
<el-form-item label="approver" :prop="`${propPrefix}.user`">
<el-input v-model="" placeholder="approver"></el-input>
</el-form-item>
<el-form-item label="project area" :prop="`${propPrefix}.region`">
<el-select v-model="" placeholder="project area">
<el-option label="Region I" value="shanghai"></el-option>
<el-option label="Region II" value="beijing"></el-option>
</el-select>
</el-form-item>
</div>
</template>
<script>
export const auditFormData = () => ({
user: '',
region: ''
})
export default {
name: 'auditFormItem',
props: {
value: {
type: Object,
default: () => auditFormData()
},
propPrefix: {
type: String,
default: ''
}
},
data() {
return {
form:
}
},
watch: {
value(newVal) {
= newVal
},
form(newVal) {
this.$emit('input', newVal)
}
}
}
</script>
on account ofelement-ui
When validating a form, it is actually a validation of themodel
The data bound on it is validated, so in order to be able to perform the validation on the data correctly, we need to add theauditFormItem
Implemented in the componentv-model
Instructions.
auditFormItem
integrated componentpropPrefix
attribute is used to specify the prefix of the form item, making it easy for us to embed it in theel-form
When a form item can be correctly bound in theprop
Properties.
auditFormData
The function returns the default data for the current form item. By executing this function, the parent component can perform the correct initialization of the child form. Not only that, in this way, we bind the data of each child form item to the component, avoiding the problem of a large amount of form item data in the parent component's data, which makes it difficult to maintain. Each child form maintains its own data without interfering with each other.
How to embed an existing project
Next we try to set theauditFormItem
component is embedded in thePapers
<template>
<el-form ref="form" :model="form" label-width="140px">
<!-- Other form items -->
<!-- ... -->
<audit-form-item v-model="" propPrefix="audit"></audit-form-item>
</el-form>
</template>
<script>
import auditFormItem, { auditFormData } from './components/audit/'
export default {
components: {
auditFormItem
},
data() {
return {
form: {
audit: auditFormData()
}
}
}
}
</script>
How to calibrate
After the above operation, we realized that a form is split into multiple sub-form items, then how to do form validation?
We know that inelement-ui
There are two ways to validate a form item in:
One is in theel-form
uplinkrules
attribute, which passes theprop
Performs indexing and automatically checksums bound form items.
The other is in theel-form-item
uplinkrules
attribute, which will validate a single form entry.
For the scenario in which we are splitting the form items, we choose the second way in which theel-form-item
uplinkrules
attribute, and then maintains in each subcomponent therules
. If there are some generalized checksum rules, we can also include them in theaudit/
file is maintained in theimport
The way it was introduced.
How to handle linkage calibration
In complex forms, we may need to perform linked checks on multiple form items, e.g., real-time checking of the legitimacy of a form item when thebecause of
shanghai
whencannot be null when
because of
beijing
whenMust be empty.
So how do you handle this kind of linked calibration?
We can find out more about this in theel-form
component in which it resides, define a validate method that can be accessed via theelement-ui
offeredvalidateField
method for a specific calibration.
<audit-form-item v-model="" propPrefix="audit" @validate="validate"></audit-form-item>
methods: {
validate(fields) {
this.$(fields)
}
}
after thataudit/
file.$emit('validate', fields)
method to validate the current form item.
How to handle cross-component linkage checks
After we split the form into multiple subcomponents, there may also be linkage checks between different subcomponents, e.g., when subcomponent 1 in thebecause of
shanghai
In case of subcomponent 2, theIt cannot be empty.
I actually haven't come up with a good solution for this problem at the moment, it's currently on theel-form
component in which it resides, defines additional checksum rules, and then binds them to a blankel-form-item
Up.
<el-form-item label="" label-width="0" prop="_form_validate_"></el-form-item>
rules: {
_form_validate_: {
validator: (rule, value, callback) => {
// Linkage checking logic
}
}
}
Also consider using vuex to maintain data that needs to be shared across components.
const crossCmpConfig = {
state: {
region: '',
},
mutations: {
UPDATE: (state, { key, val }) => {
state[key] = val
},
},
}
export default crossCmpConfig
multilayered nesting
Based on the above approach, it's easy to think that we could even continue on theaudit/
file, go ahead and embed other subcomponents, for example:audit/audit-info/
, which then continues to be embedded in the same way through theaudit/
Documentation.
concluding remarks
The above is a summary of some of my experiences in dealing with complex forms in my daily development, I hope it will help you.