我是vue.js的新手,我正在尝试使用Vue,vuetify和vuelidate制作一个表单。如果我不 Package v-text-field:没问题。如果我把它 Package 成组件:问题。值没有更新,并且出现警告“[Vue warn] Set operation on key“model”failed:目标为只读。“
你可以看到在这个沙盒上发生了什么:
https://codesandbox.io/s/distracted-newton-dx9p4s?file=/src/components/Form.vue
看看代码(我正在关注的):
Form.vue:
<script setup>
import { reactive } from "vue";
import { useVuelidate } from "@vuelidate/core";
import { required } from "@vuelidate/validators";
import StyledInput from "./StyledInput.vue";
import StyledInput2 from "./StyledInput2.vue";
import StyledInput3 from "./StyledInput3.vue";
const formData = reactive({
username: "",
username2: "",
username3: "",
username4: "",
});
const rules = {
username: { required },
username2: { required },
username3: { required },
username4: { required },
};
const v$ = useVuelidate(rules, formData);
</script>
<template>
<v-text-field
v-model="formData.username"
label="Username 1"
@input="v$.username.$touch;"
@blur="v$.username.$touch"
variant="outlined"
></v-text-field>
<div>{{ formData.username }}</div>
<StyledInput
:model="formData.username2"
label="Username 2"
:fieldData="v$.username2"
/>
<div>{{ formData.username2 }}</div>
<StyledInput2
:model="formData.username3"
label="Username 3"
:fieldData="v$.username3"
/>
<div>{{ formData.username3 }}</div>
<StyledInput3
v-model="formData.username4"
label="Username 4"
:fieldData="v$.username4"
/>
<div>{{ formData.username4 }}</div>
</template>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
MyInput.vue:
<script setup>
const props = defineProps({
model: {
//type: String,
required: true,
},
label: {
type: String,
required: true,
},
fieldData: {
type: Object,
required: true,
},
});
</script>
<template>
<v-text-field
v-model="props.model"
:label="props.label"
:error-messages="props.fieldData.$errors.map((e) => e.$message)"
@input="props.fieldData.$touch;"
@blur="props.fieldData.$touch"
variant="outlined"
></v-text-field>
</template>
<style></style>
StyledInput.vue:
<script setup>
import MyInput from "./MyInput.vue";
const props = defineProps({
model: {
//type: String,
required: true,
},
label: {
type: String,
required: true,
},
fieldData: {
type: Object,
required: true,
},
});
</script>
<template>
<MyInput v-bind="props"></MyInput>
</template>
<style></style>
我在沙盒上提供了更多不同的尝试。我不明白我做错了什么,有什么想法吗?
谢谢你
1条答案
按热度按时间t5zmwmid1#
[Vue warn]对关键字“model”的设置操作失败:目标为只读。
这个警告来自于一个prop的突变,这发生在v-text-field上:
Props应该被视为只读,因为它们代表单向数据流。为了绕过这个限制,可以将所需的变化发送给父组件,父组件可以安全地在原始对象上执行变化。这可以与使用v-model很好地配对,因为接收v-model的自定义子组件将其作为prop接收,并将更改发送给父组件。
给定的codesandbox并不是最简单的例子,因为prop有两个子组件,但它可以做到。我会在StyledInput上设置v-model:
Form.vue
在第一个子组件中,定义v-model prop
modelValue
,然后继续将prop传递给下一个子组件并设置emit:StyledInput.vue
然后在下一个子组件中基本上重复相同的事情,但现在还设置了v-text-field的
value
属性,并根据input
事件发出更改:MyInput.vue
v-text-field将显示
props.modelValue
的值,但不会覆盖它。当用户输入新值时,具有新值的事件将一直发送到Form.vue,在那里进行实际的变化。(v-model)。一旦设置了新的值,它就会向下流动,重新显示在v-text-field的:value
中。这一切发生得如此之快,以至于看起来天衣无缝。updated codesandbox
最后,作为一个提示,如果在多个级别的组件之间传递数据感觉太混乱或太难以维护,请考虑使用像Pinia这样的全局存储