Location>code7788 >text

How I'm using vue2+element-ui to handle responsible forms and avoid single-file oversize issues

Popularity:949 ℃/2024-08-16 14:32:29

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.vueThe 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-formCenter.

This has several advantages for a project that doesn't have a well organized, componentized file to begin with:

  1. Minor changes! Subsequent additions of new form items will basically not change the previous code
  2. Component-based! Logically split form items and embed them anywhere!
  3. 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-uiDocumentation for thisform (document)As an example, next try to implement it in our way

Let's start by assuming that we currently have avuefile./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-uiform 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, acomponentsdirectory, and then in thecomponentsdirectory to create aauditdirectory, and in theauditdirectory to create afile for components related to the approval process. If there are subsequent components that are onlyaudit/components that are only used in the file, I also put them in theauditCatalog. 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-uiWhen validating a form, it is actually a validation of themodelThe data bound on it is validated, so in order to be able to perform the validation on the data correctly, we need to add theauditFormItemImplemented in the componentv-modelInstructions.

auditFormItemintegrated componentpropPrefixattribute is used to specify the prefix of the form item, making it easy for us to embed it in theel-formWhen a form item can be correctly bound in thepropProperties.

auditFormDataThe 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 theauditFormItemcomponent 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-uiThere are two ways to validate a form item in:

One is in theel-formuplinkrulesattribute, which passes thepropPerforms indexing and automatically checksums bound form items.
The other is in theel-form-itemuplinkrulesattribute, 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-itemuplinkrulesattribute, 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 theimportThe 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 ofshanghaiwhencannot be null whenbecause ofbeijingwhenMust be empty.

So how do you handle this kind of linked calibration?

We can find out more about this in theel-formcomponent in which it resides, define a validate method that can be accessed via theelement-uiofferedvalidateFieldmethod 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 ofshanghaiIn 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-formcomponent in which it resides, defines additional checksum rules, and then binds them to a blankel-form-itemUp.

<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.