vue.js 自动换行的v-text-field导致警告并且不刷新数据

f4t66c6m  于 2023-04-07  发布在  Vue.js
关注(0)|答案(1)|浏览(223)

我是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>

我在沙盒上提供了更多不同的尝试。我不明白我做错了什么,有什么想法吗?
谢谢你

t5zmwmid

t5zmwmid1#

[Vue warn]对关键字“model”的设置操作失败:目标为只读。
这个警告来自于一个prop的突变,这发生在v-text-field上:

<v-text-field
  v-model="props.model"
  ...
></v-text-field>

Props应该被视为只读,因为它们代表单向数据流。为了绕过这个限制,可以将所需的变化发送给父组件,父组件可以安全地在原始对象上执行变化。这可以与使用v-model很好地配对,因为接收v-model的自定义子组件将其作为prop接收,并将更改发送给父组件。
给定的codesandbox并不是最简单的例子,因为prop有两个子组件,但它可以做到。我会在StyledInput上设置v-model:

Form.vue

<StyledInput
    v-model="formData.username2"
    label="Username 2"
    :fieldData="v$.username2"
  />

在第一个子组件中,定义v-model prop modelValue,然后继续将prop传递给下一个子组件并设置emit:

StyledInput.vue

const props = defineProps({
  modelValue: {
    //type: String,
    required: true,
  },
})
<MyInput
  v-bind="props"
  @update:modelValue="$emit('update:modelValue', $event)"
></MyInput>

然后在下一个子组件中基本上重复相同的事情,但现在还设置了v-text-field的value属性,并根据input事件发出更改:

MyInput.vue

const props = defineProps({
  modelValue: {
    //type: String,
    required: true,
  },
<v-text-field
  :value="props.modelValue"
  @input="$emit('update:modelValue', $event.target.value)"
></v-text-field>

v-text-field将显示props.modelValue的值,但不会覆盖它。当用户输入新值时,具有新值的事件将一直发送到Form.vue,在那里进行实际的变化。(v-model)。一旦设置了新的值,它就会向下流动,重新显示在v-text-field的:value中。这一切发生得如此之快,以至于看起来天衣无缝。
updated codesandbox
最后,作为一个提示,如果在多个级别的组件之间传递数据感觉太混乱或太难以维护,请考虑使用像Pinia这样的全局存储

相关问题