如何仅使用 Vuelidate 验证 onblur?

How to validate only onblur with Vuelidate?

从我的父组件,我以这种方式调用我的自定义输入子组件:

<custom-input
  v-model="$v.form.userName.$model"
  :v="$v.form.userName"
  type="text"
/>

这是我的自定义输入组件:

<template>
  <input
    v-bind="$attrs"
    :value="value"
    v-on="inputListeners"
    :class="{ error: v && v.$error }"
  >
</template>

<script>
export default {
  inheritAttrs: false,
  props: {
    value: {
      type: String,
      default: ''
    },
    v: {
      type: Object,
      default: null
    }
  },
  computed: {
    inputListeners () {
      const vm = this
      return Object.assign({},
        this.$listeners,
        {
          input (event) {
            vm.$emit('blur', event.target.value)
          }
        }
      )
    }
  }
}
</script>

这会从输入字段中输入的第一个字符触发验证错误(这可以说是糟糕的用户体验,所以我真的不明白为什么这是默认行为)。

无论如何,如何仅在 blur 事件上触发此类错误?

这不是默认行为 - 这是您的代码!

只有在通过调用 $touch method. But when you are using $model property ($v.form.userName.$model) for v-model, it calls $touch automatically - docs

将字段标记为脏后,Vuelidate 才会验证(并引发错误)

所以要么不要使用 $model 进行绑定,而是在 blur 事件中(或任何你想要的时候)自己调用 $touch

或者您可以尝试使用 .lazy modifier on v-model but that is supported only on native input elements (support for custom components is long time request)

下面的例子展示了如何自己实现它....

Vue.use(window.vuelidate.default)

Vue.component('custom-input', {
  template: `
  <input
    v-bind="$attrs"
    :value="value"
    v-on="inputListeners"
    :class="status(v)"
  ></input>
  `,
  inheritAttrs: false,
  props: {
    value: {
      type: String,
      default: ''
    },
    v: {
      type: Object,
      default: null
    },
    lazy: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    inputListeners() {
      const listeners = { ...this.$listeners }
      const vm = this
      const eventName = this.lazy ? 'change' : 'input'
      
      delete listeners.input
      listeners[eventName] = function(event) {
        vm.$emit('input', event.target.value)
      }
            
      return listeners
    }
  },
  methods: {
    status(validation) {
      return {
        error: validation.$error,
        dirty: validation.$dirty
      }
    }
  }
})

const { required, minLength } = window.validators

new Vue({
  el: "#app",
  data: {
    userName: ''
  },
  validations: {
    userName: {
      required,
      minLength: minLength(5)
    }
  }
})
input {
  border: 1px solid silver;
  border-radius: 4px;
  background: white;
  padding: 5px 10px;
}

.dirty {
  border-color: #5A5;
  background: #EFE;
}

.dirty:focus {
  outline-color: #8E8;
}

.error {
  border-color: red;
  background: #FDD;
}

.error:focus {
  outline-color: #F99;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vuelidate/dist/vuelidate.min.js"></script>
<script src="https://unpkg.com/vuelidate/dist/validators.min.js"></script>

<div id="app">
  <custom-input v-model="$v.userName.$model" :v="$v.userName" type="text" lazy></custom-input>
  <pre>Model: {{ userName }}</pre>
  <pre>{{ $v }}</pre>
</div>

尝试从 blur 事件的处理程序发出输入事件,因此:

而不是:

v-on="inputListeners"

设置

@blur="$emit('input', $event.target.value)"