В миддл и бэкенд системах навыки разработки и оптимизации сложных форм

JavaScript Vue.js

Формы незаменимы в ежедневной разработке мидл и бэкенд систем.Когда форм много, типа сотни полей (это не преувеличение, реальность кровавая) код часто становится сложным и трудным в сопровождении. Различные проверки формы динамической связи в Интернете, несомненно, сделают наш процесс разработки страницы еще хуже. В этой статье мы объединим наши обычные привычки разработки, чтобы поделиться тем, как справляться со сложной проверкой формы при разработке больших форм и как разделить форму. уменьшить накопление избыточного кода в одном файле.

проверка формы

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

Если в это время добавляется новая проверка, предполагая, что если тип бизнеса — уход за кожей, название компании не требуется, то нам необходимо отслеживать значение типа бизнеса, как указано выше, и делать соответствующие суждения. форма увеличивается, наши часы будут все больше и больше, правила также будут разбросаны по разным местам, что неизбежно повлечет за собой трудности в последующем сопровождении кода, и человек, который берет на себя, должен также аккуратно вносить в него изменения.

Оптимизация проверки формы с использованием вычислений

Единообразное обращение с правилами как со значением в вычисляемом свойстве вместо помещения их в данные позволяет избежать необходимости частого применения правил в данных и позволяет избежать разбросанных по странице элементов правил.

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' }
      ]
    }
  }
}

После переключения на вычисляемый возникает проблема: проверка срабатывает сразу при первоначальной загрузке страницы или при изменении соответствующего значения, используемого в вычисляемом. Похоже, что опыт не очень хороший,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>

Проблема передачи данных с двоюродным компонентом

После разделения большой формы иногда необходимо установить связь между одноуровневыми компонентами, например, поле в кооперативной форме должно быть определено в соответствии с полем в базовой форме. Обычно я использую vuex для решения этой проблемы, сохраняю ее в vuex при изменении значения base-form, а 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' }
      ]
    }
  }
}

благодарный

Этот обмен окончен здесь. Спасибо за прочтение. Если эта статья была вам полезна, не забудьте поставить палец вверх ❤️.

Если в этой статье есть какие-либо ошибки или недостатки, пожалуйста, исправьте меня в области комментариев, и если есть лучший способ, пожалуйста, дайте мне совет в области комментариев!