首页 > 解决方案 > 输入时表单输入未得到验证 (@input),只有 @blur 有效

问题描述

我正在使用带有输入数据验证的组合框(Vuelidate):

<template>
    <v-combobox
        clearable
        v-model="surname"
        :items="commonSurnames"
        label="Surname"
        placeholder="Type in the surname"
        class="pt-5 pb-5"
        :error-messages="surnameErrors"
        @input="$v.surname.$touch()"
        @blur="$v.surname.$touch()">
    </v-combobox>
</template>

<script>
import { validationMixin } from 'vuelidate'
import { required, maxLength } from 'vuelidate/lib/validators'

export default {
    mixins: [validationMixin],
    validations: {
        surname: {
            required,
            maxLength: maxLength(30),
            validSurname(surname) {
                return (
                    /^[a-zA-Z]-?*.+$/.test(surname)
                )
            }
        },
    name: 'Surnames',

    data() {
        return {
            surname: '',
            [...]
    },
    methods: {
        [...]
    },
    computed: {
        surnameErrors() {
            const errors = []
            if (!this.$v.surname.$dirty) return errors
            !this.$v.surname.validSurname && errors.push('Format must be like: Smith or Smith-Wesson')
            !this.$v.surname.maxLength && errors.push('Surname must be at most 30 characters long.')
            !this.$v.surname.required && errors.push('Surname is required.')
            return errors
    }
}
</script>

组件版本:

  "dependencies": {
    "@vue/compiler-sfc": "^3.0.0",
    "core-js": "^3.6.5",
    "vue": "^2.6.11",
    "vuelidate": "^0.7.5",
    "vuetify": "^2.2.11"
  },

我想我在Vuetify 文档中做了所有事情,但是我的表单得到的验证与文档中的内容有点不同:我可以超过 30 个字符的限制,而不会在输入时收到通知。我只有在输入失去焦点时才知道。RegEx 验证的情况相同:接受任何值而没有错误通知。如果该值无效,我会在离开输入字段时收到通知。

从文档中复制示例时我是否遗漏了什么,或者@input监听器工作不正确?还是v-combobox不能以这种方式验证?

标签: javascriptvue.jsvuetify.jsvuelidate

解决方案


我曾经有一个组件包装器v-comboboxv-autocomplete并且v-select(是的,单个多用途包装器)。我建议在包装器中使用下面的代码,以避免复制粘贴修复/解决方法。

一般来说,解决方法需要查找 Vuetify 源。这导致了操纵和errorBucket倾听。valid@update:search-input

此外,您可能想要发出'input'. 它需要一个小的调整来抑制传播到v-combobox值,否则它会破坏自动完成行为。因此if (this.search) { return; }

完整示例:Codepen

Vue.component(
  'my-combobox', {
  template: `
      <v-combobox
         ref="combobox"
         outlined dense
         v-model="selection"
         v-bind="{ ...$attrs, items, rules: validationRules }"
         v-on="$listeners"
         @update:search-input="onSearch"
         @focus="touched = true"></v-combobox>
      `,
  props: {
    value: String,
    items: Array,
    required: Boolean,
    rules: Array,
  },
  data() {
    return {
      selection: null,
      search: null,
      touched: false,
    };
  },
  computed: {
    validationRules() {
      return [
        ...(this.rules || []),
        (v) => !this.required || (v?.length ?? 0) > 0 || 'Value is required',
      ];
    },
  },
  methods: {
    onSearch(v) {
      if (!this.touched) return;
      this.search = v;
      const $self = this.$refs.combobox;
      $self.errorBucket = this.validationRules.filter(f => f(v) !== true);
      $self.valid = $self.errorBucket.length === 0;
      this.$emit('input', v);
    },
  },
  watch: {
    selection: {
      handler(v) {
        this.$emit('input', v);
      },
    },
    value: {
      immediate: true,
      handler(v) {
        if (this.search) { return; }
        this.selection = v;
      },
    },
  },
});

推荐阅读