我有一个旧的
Vue2
登录页面代码。其中一部分正在检查用户名输入字段:
...
<validation-observer ref="ref-id" v-slot="{ invalid }">
<v-form>
<v-card-text>
<validation-provider
v-slot="{ errors }"
rules="rulename"
name="username"
>
<v-text-field
v-model="input.username"
label="username"
prepend-icon="mdi-account-circle"
:error-messages="errors"
></v-text-field>
</validation-provider>
...
</v-card-text>
</v-form>
</validation-observer>
...
现在我正在尝试使用新版本创建相同的代码
Vuetify
和vee-validate
(3
和4
)
我可以使用新版本的
v-text-field
创建 Vuetify
:
<vee-validation-form as="v-form">
<v-card-text>
<!-- <vee-validation-field as="v-text-field" -->
<v-text-field
v-model="input.username"
label="username"
prepend-icon="mdi-account-circle"
:error-messages="errors"
></v-text-field>
<!-- ></vee-validation-field> -->
</v-card-text>
</vee-validation-form>
哪里
此代码至少显示
username
输入元素。
但是当我尝试使用
<vee-validation-field as="v-text-field"
而不是 <v-text-field
时,它显示错误:
ERROR
Cannot read properties of undefined (reading 'split')
TypeError: Cannot read properties of undefined (reading 'split')
at normalizeFormPath (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:100:26)
at ReactiveEffect.eval [as fn] (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:1603:70)
at ReactiveEffect.run (webpack-internal:///./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js:217:19)
at get value [as value] (webpack-internal:///./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js:1178:33)
at unref (webpack-internal:///./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js:1057:29)
at _useFieldValue (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:1141:70)
at useFieldState (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:1044:54)
at _useField (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:1618:72)
at useField (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:1597:12)
at setup (webpack-internal:///./node_modules/vee-validate/dist/vee-validate.esm.js:2038:164)
问题是:如何将
v-text-field
组件与vee-validate
一起使用?据我正确理解,新的 ValidationObserver
中没有 ValidationPbserver
和 vee-validate v4
组件。
Field 组件需要一个
name
属性,当它尝试对值调用 split()
时会抛出错误。只需设置一个名称,错误就消失了:
<Field as="v-text-field"
name="username"
...
></Field>
但是,
label
是Field
组件的道具,但它仅将属性(即非道具)传递给自定义输入组件(请参阅code),因此您无法将标签传递给v-text -场地。此外,您还必须通过表格获取错误消息。
目前看来使用
:as
比解决方案更麻烦。可能更好地坚持使用插槽:
<vee-validation-field
v-slot="{ field, errors }"
name="username"
rules="required|needsL"
v-model="username"
>
<v-text-field
v-model="field.value"
v-bind="field"
label="username"
prepend-icon="mdi-account-circle"
:error-messages="errors"
/>
</vee-validation-field>
(由于 vee-validate 中的
问题,VTextField 上有些重复的
v-bind
和 v-model
对于他们来说是必要的)
const { createApp, ref } = Vue;
const { createVuetify } = Vuetify
const vuetify = createVuetify()
VeeValidate.defineRule('required', VeeValidateRules.required)
VeeValidate.defineRule('needsL', v => v.toLowerCase().includes('L') || 'Input something with an `l`')
const app = {
components: {
'vee-validation-form': VeeValidate.Form,
'vee-validation-field': VeeValidate.Field,
},
setup(){
return {
username1: ref('user 1'),
username2: ref('user 2'),
}
}
}
createApp(app).use(vuetify).mount('#app')
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify.min.css" />
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<div id="app">
<v-app>
<v-main>
<vee-validation-form as="v-form" v-slot="{errors}">
<v-card-text>
Field from :as
<vee-validation-field as="v-text-field"
name="username1"
v-model="username1"
prepend-icon="mdi-account-circle"
:error-messages="errors.username1"
rules="required|needsL"
></vee-validation-field>
Field in slot
<vee-validation-field
v-slot="{ field, errors }"
v-model="username2"
name="username2"
rules="required|needsL"
>
<v-text-field
v-model="field.value"
v-bind="field"
label="username"
prepend-icon="mdi-account-circle"
:error-messages="errors"
/>
</vee-validation-field>
</v-card-text>
</vee-validation-form>
</v-main>
</v-app>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vee-validate/4.10.8/vee-validate.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@vee-validate/[email protected]/dist/vee-validate-rules.min.js"></script>
总的来说,上述方法是正确的,但犯了一个重大错误。
就在一周前,我不得不处理我们的大型项目的迁移,该项目有大量的形式,从 Vuetify 2 到 3,从 Vee-validate 3 到 4。在花费了相当多的时间之后,我想提出以下建议研究问题和处理具体案例的时间。我不会继承之前的答案,而是会在一条消息中概述我的整个解决方案,方便寻求答案的人立即掌握主题。
在确定validation-observer和validation-provider组件时,一切都是准确的。就我而言,我注册了名为 和 的 Form 组件和 Field 。对于那些迁移真实项目的人来说,这将节省大量时间,避免重写组件名称。
app
.component('validation-observer', Form)
.component('validation-provider', Field)
现在,我们应该将 Field 组件视为主要输入组件,而 v-text-field 只是一个视觉对象,它仅与 Field 交换数据,而 Field 现在是验证提供程序。
根据文档,我们可以通过插槽与验证提供程序和我们的字段进行交互,但不是field,而是componentField。它将包含带有 modelValue 键而不是 value 的正确对象,使我们能够正确访问组件的值。这确保了与 Vue 3 的正确兼容性,因为在 2 版本中使用了 value。因此,默认情况下不需要使用 as 参数。包含内部组件的 Field 组件不会显示为标准输入字段,我们在输入组件中通过 v-bind 使用 componentField 插槽。
所以我们需要采取2个行动:
以下是正确代码的示例(如果需要,请使用您的组件名称):
<validation-observer
v-slot="{ handleSubmit }"
>
<validation-provider
v-slot="{ componentField, errors }"
v-model="input.username"
name="Username"
rules="required"
>
<v-text-field
v-bind="componentField"
:error-messages="errors"
label="Username"
prepend-icon="mdi-account-circle"
/>
</validation-provider>
</validation-observer>
现在我们的字段已经与验证组件Field(validation-provider)正确同步了。
对于字段(验证观察者)插槽,请参阅文档。