Написание компонентов формы с помощью асинхронного валидатора

внешний интерфейс Element дизайн Vue.js

Во фронтенд-разработке проверка формы — очень распространенная функция, некоторые библиотеки пользовательского интерфейса, такие какant.designа такжеElement uiТам достигли компонентов формы функции четности.async-validatorДанные проверки могут быть асинхронной библиотекой, ant.design с компонентами пользовательского интерфейса Form Element, используемыми async-validator. В этой статье будет кратко объяснено основное использование асинхронного валидатора и использование библиотеки, реализующей простой компонент формы с функцией проверки.

1. Базовое использование асинхронного валидатора

Функция асинхронного валидатора заключается в проверке законности данных и выдаче оперативной информации в соответствии с правилами проверки.

Ниже показано самое простое использование асинхронного валидатора.

import AsyncValidator from 'async-validator'
// 校验规则
const descriptor = {
  username: [
    {
      required: true,
      message: '请填写用户名'
    },
    {
      min: 3,
      max: 10,
      message: '用户名长度为3-10'
    }
  ]
}
// 根据校验规则构造一个 validator
const validator = new AsyncValidator(descriptor)
const data = {
  username: 'username'
}
validator.validate(model, (errors, fields) => {
  console.log(errors)
})

Когда данные не соответствуют правилам проверки, соответствующее сообщение об ошибке может быть получено в функции обратного вызова validator.validate.

Когда общие правила проверки в асинхронном валидаторе не могут соответствовать требованиям, мы можем написать собственные функции проверки для проверки данных. Простая функция проверки выглядит следующим образом.

function validateData (rule, value, callback) {
  let err
  if (value === 'xxxx') {
      err = '不符合规范'
  }
  callback(err)
}
const descriptor = {
  complex: [
      {
        validator: validateData
      }
  ]
}
const validator = new AsyncValidator(descriptor)

async-validator поддерживает асинхронную проверку данных, поэтому при написании пользовательской функции проверки обратный вызов в функции проверки должен вызываться независимо от того, проходит проверка или нет.

2. Напишите компонент формы и компонент FormItem

Теперь, когда вы знаете, как использовать асинхронный валидатор, как объединить эту библиотеку с написанным компонентом формы.

Реализовать идеи

Используйте картинку, чтобы описать идею реализации.

Form与FormItem组件的实现思路

Компонент формы

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

Компонент формы также должен знать, сколько компонентов FormItem необходимо проверить. В основном,Связь между родительским и дочерним компонентамиОн реализуется привязкой событий к дочерним компонентам, но здесь используется слот, и события дочерних компонентов не могут быть отслежены. Здесь вы можете передать его в компонент формы$onСлушайте событие и инициируйте пользовательское событие компонента формы до того, как FormItem будет смонтирован или уничтожен.

Согласно этой идее, сначала пишем компонент Form.

<template>
  <form class="v-form">
    <slot></slot>
  </form>  
</template>
<script>
import AsyncValidator from 'async-validator'
export default {
  name: 'v-form',
  componentName: 'VForm', // 通过 $options.componentName 来找 form 组件
  data () {
    return {
      fields: [], // field: {prop, el},保存 FormItem 的信息。
      formError: {}
    }
  },
  computed: {
    formRules () {
      const descriptor = {}
      this.fields.forEach(({prop}) => {
        if (!Array.isArray(this.rules[prop])) {
          console.warn(`prop 为 ${prop} 的 FormItem 校验规则不存在或者其值不是数组`)
          descriptor[prop] = [{ required: true }]
          return
        }
        descriptor[prop] = this.rules[prop]
      })
      return descriptor
    },
    formValues () {
      return this.fields.reduce((data, {prop}) => {
        data[prop] = this.model[prop]
        return data
      }, {})
    }
  },
  methods: {
    validate (callback) {
      const validator = new AsyncValidator(this.formRules)
      validator.validate(this.formValues, (errors) => {
        let formError = {}
        if (errors && errors.length) {
          errors.forEach(({message, field}) => {
            formError[field] = message
          })
        } else {
          formError = {}
        }
        this.formError = formError
        // 让错误信息的顺序与表单组件的顺序相同
        const errInfo = []
        this.fields.forEach(({prop, el}, index) => {
          if (formError[prop]) {
            errInfo.push(formError[prop])
          }
        })
        callback(errInfo)
      })
    }
  },
  props: {
    model: Object,
    rules: Object
  },
  created () {
    this.$on('form.addField', (field) => {
      if (field) {
        this.fields = [...this.fields, field]
      }
    })
    this.$on('form.removeField', (field) => {
      if (field) {
        this.fields = this.fields.filter(({prop}) => prop !== field.prop)
      }
    })
  }
}
</script>

Компонент FormItem

Компонент FormItem намного проще: сначала найдите компонент Form, который его содержит. Затем соответствующая информация об ошибке может быть рассчитана в соответствии с formError.

<template>
  <div class="form-item">
    <label :for="prop" class="form-item-label" v-if="label">
      {{ label }}
    </label>
    <div class="form-item-content">
      <slot></slot>
    </div>
  </div>
</template>
<script>
export default {
  name: 'form-item',
  computed: {
    form () {
      let parent = this.$parent
      while (parent.$options.componentName !== 'VForm') {
        parent = parent.$parent
      }
      return parent
    },
    fieldError () {
      if (!this.prop) {
        return ''
      }
      const formError = this.form.formError
      return formError[this.prop] || ''
    }
  },
  props: {
    prop: String,
    label: String
  }
}
</script>

FormItem также должен инициировать некоторые пользовательские события компонента Form в обработчиках mount и beforeDestroy.

<script>
export default {
  // ...
  methods: {
    dispatchEvent (eventName, params) {
      if (typeof this.form !== 'object' && !this.form.$emit) {
        console.error('FormItem必须在Form组件内')
        return
      }
      this.form.$emit(eventName, params)
    }
  },
  mounted () {
    if (this.prop) {
      this.dispatchEvent('form.addField', {
        prop: this.prop,
        el: this.$el
      })
    }
  },
  beforeDestroy () {
    if (this.prop) {
      this.dispatchEvent('form.removeField', {
        prop: this.prop
      })
    }
  }
}
</script>

Наконец создайте новыйindex.jsЭкспортируйте написанный компонент.

import VForm from './Form.vue'
import FormItem from './FormItem.vue'

export {
  VForm,
  FormItem
}

3. Как использовать

Функция проверки формы находится в компоненте Form. пройти через$refВы можете получить доступ к компоненту Form и вызвать функцию проверки, чтобы получить соответствующую информацию проверки.

Используйте следующим образом:

<template>
  <v-form :model="formData" :rules="rules" ref="form">
    <form-item label="手机号" prop="tel">
      <input type="tel" maxlength="11" v-model.trim="formData.tel"/>
    </form-item>
    <button @click="handleSubmit">保存</button>
  </v-form>
</template>
<script>
  import { VForm, FormItem } from './common/Form'
  export default {
    data () {
      return {
        formData: {
          tel: ''
        },
        rules: {
          tel: [
            {required: true, message: '您的手机号码未输入'},
            {pattern: /^1[34578]\d{9}$/, message: '您的手机号码输入错误'}
          ]
        }
      }
    },
    methods: {
      handleSubmit () {
        this.$refs.form.validate(errs => {
          console.log(errs)
        })
      }
    },
    components: {
      VForm,
      FormItem
    }
  }
</script>

полный код нажмитездесь.

4. Резюме

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

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

использованная литература