Skip to main content
 首页 » 编程设计

validation之使用 vuelidate 验证嵌套对象时,在 vuetify 中显示错误消息

2026年05月17日48www_RR

我正在使用 vuelidate使用 vuetifyjs 验证我的表单输入并显示错误消息.我设法进行了基本的对象验证,并且能够显示错误消息。

但是,当我验证集合时,我在显示错误消息时遇到了问题。

问题

示例数据结构:

contact: { 
  websites: [ 
    { 
      url: 'http://www.something.com', 
      label: 'Website', 
    } 
  ] 
} 

示例验证:
validations: { 
  websites: { 
    $each: { 
      url: { 
        url, 
      } 
    } 
  }, 
} 

示例模板:
<template v-for="(website, index) in websites"> 
        <v-layout row :key="`website${index}`"> 
          <v-flex xs12 sm9 class="pr-3"> 
            <v-text-field 
                    label="Website" 
                    :value="website.url" 
                    @input="$v.websites.$touch()" 
                    @blur="$v.websites.$touch()" 
                    :error-messages="websiteErrors" 
            ></v-text-field> 
          </v-flex> 
        </v-layout> 
</template> 

示例计算错误消息:
websiteErrors() { 
        console.log('websites',this.$v.websites) // contains $each 
        const errors = [] 
        if (!this.$v.websites.$dirty) { 
          return errors 
        } 
        // Issue is that all of them show must be valid, even if they are valid.  
        // Validation is basically broken. 
        // I also tried this.$v.websites.$each.url 
        !this.$v.websites.url && errors.push('Must be valid url') 
        return errors 
      }, 

示例方法(更新,还尝试了传递索引的方法):
websiteErrors(index) { 
        console.log('this.$v.entity.websites', this.$v.entity.websites.$each.$iter, this.$v.entity.websites.$each.$iter[index], this.$v.entity.websites.minLength, this.$v.entity.websites.$each.$iter[index].url) 
        const errors = [] 
        if (!this.$v.entity.websites.$dirty) { 
          return errors 
        } 
 
        !this.$v.entity.websites.$each.$iter[index].url && errors.push('Must be valid url') 
        return errors 
      }, 

但是,当我这样做时,它总是正确的,因此永远不会显示错误。

预期

我想让与 vuelidate sub-collection validation 中看到的相同的示例工作不同之处在于我想以编程方式生成消息而不是在模板中循环。

引用

vuelidate 提供的示例:
import { required, minLength } from 'vuelidate/lib/validators' 
 
export default { 
  data() { 
    return { 
      people: [ 
        { 
          name: 'John' 
        }, 
        { 
          name: '' 
        } 
      ] 
    } 
  }, 
  validations: { 
    people: { 
      required, 
      minLength: minLength(3), 
      $each: { 
        name: { 
          required, 
          minLength: minLength(2) 
        } 
      } 
    } 
  } 
} 
 
<div> 
  <div v-for="(v, index) in $v.people.$each.$iter"> 
    <div class="form-group" :class="{ 'form-group--error': v.$error }"> 
      <label class="form__label">Name for {{ index }}</label> 
      <input class="form__input" v-model.trim="v.name.$model"/> 
    </div> 
    <div class="error" v-if="!v.name.required">Name is required.</div> 
    <div class="error" v-if="!v.name.minLength">Name must have at least {{ v.name.$params.minLength.min }} letters.</div> 
  </div> 
  <div> 
    <button class="button" @click="people.push({name: ''})">Add</button> 
    <button class="button" @click="people.pop()">Remove</button> 
  </div> 
  <div class="form-group" :class="{ 'form-group--error': $v.people.$error }"></div> 
  <div class="error" v-if="!$v.people.minLength">List must have at least {{ $v.people.$params.minLength.min }} elements.</div> 
  <div class="error" v-else-if="!$v.people.required">List must not be empty.</div> 
  <div class="error" v-else-if="$v.people.$error">List is invalid.</div> 
  <button class="button" @click="$v.people.$touch">$touch</button> 
  <button class="button" @click="$v.people.$reset">$reset</button> 
  <tree-view :data="$v.people" :options="{rootObjectKey: '$v.people', maxDepth: 2}"></tree-view> 
</div> 

请您参考如下方法:

出了什么问题

  • 共享计算属性导致所有兄弟共享相同错误消息的问题。 (通过内联编写解决)
  • 由于未以“ react 方式”更新数组,因此未触发 react 性(在这种情况下,请务必注意 Change Detection Caveats 而不是更新索引:我复制数组,替换项目,然后设置整个数组。)
  • 用错地方 vuelidate $each.$iter :将其从计算错误消息移至 v-for

  • 解决方案

    这是如何做到的(修复 1 和 3):
    <template v-for="(v, index) in $v.websites.$each.$iter"> 
      <v-layout row :key="`website${index}`"> 
        <v-flex xs12 sm9 class="pr-3"> 
          <v-text-field 
                        label="Website" 
                        :value="v.$model.url" 
                        @input="$v.websites.$touch()" 
                        @blur="$v.websites.$touch()" 
                        :error-messages="v.$dirty && !v.required ? ['This field is required'] : !v.url ? ['Must be a valid url'] : []" 
          /> 
        </v-flex> 
      </v-layout> 
    </template> 
    

    这就是我现在的更新方法(修复 2):
      updateWebsite(index, $event) { 
        const websites = [...this.websites]; 
        websites[index] = $event; 
        this.updateVuex(`websites`, websites) 
        this.$v.websites.$touch() 
      }, 
    

    原来是这样的:
      updateWebsite(index, $event) { 
        this.updateVuex(`websites[${index}]`, $event) 
        this.$v.websites.$touch() 
      }, 
    

    替代

    还有另一种选择,就是在这种情况下换行 website在一个组件里面。这样您就可以保留计算出的错误消息,因为它不会被共享。