使用 v-model 更新 axios 响应的子组件值

Update child component value on axios response using v-model

Vue 3

我正在尝试从 Axios 响应中更新数据变量的值。如果我在父组件中打印值,它会被打印并更新响应,但变量的值不会在子组件中更新。

我能弄清楚的是我的子组件没有收到更新的值。但是我不知道为什么会这样。

输入字段是全局组件。

Vue 3

父组件

    <template>
    <input-field title="First Name" :validation="true" v-model="firstName.value" :validationMessage="firstName.validationMessage"></input-field>
</template>
<script>
export default {
        data() {
            return {
                id: 0,
                firstName: {
                    value: '',
                    validationMessage: '',
                },
            }
        },
        created() {
            this.id = this.$route.params.id;
            this.$http.get('/users/' + this.id).then(response => {
                this.firstName.value = response.data.data.firstName;
            }).catch(error => {
                console.log(error);
            });
        },
    }
</script>

子组件

<template>
    <div class="form-group">
        <label :for="identifier">{{ title }}
            <span class="text-danger" v-if="validation">*</span>
        </label>
        <input :id="identifier" :type="type" class="form-control" :class="validationMessageClass" :placeholder="title" v-model="inputValue">
        <div class="invalid-feedback" v-if="validationMessage">{{ validationMessage }}</div>
    </div>
</template>

<script>
    export default {
        props: {
            title: {
                type: String,
                required: true,
            },
            validation: {
                type: Boolean,
                required: false,
                default: false,
            },
            type: {
                type: String,
                required: false,
                default: 'text',
            },
            validationMessage: {
                type: String,
                required: false,
                default: '',
            },
            modelValue: {
                required: false,
                default: '',
            }
        },
        emits: [
            'update:modelValue'
        ],
        data() {
            return {
                inputValue: this.modelValue,
            }
        },
        computed: {
            identifier() {
                return this.title.toLowerCase().replace(/ /g, '-').replace(/[^\w-]+/g, '');
            },
            validationMessageClass() {
                if (this.validationMessage) {
                    return 'is-invalid';
                }
                return false;
            }
        },
        watch: {
            inputValue() {
                this.$emit('update:modelValue', this.inputValue);
            },
        },
    }
</script>

您的 child 永远不会从您的 parent 收到更新的原因是,即使您更改 firstName.value,您的 child-component 也不会 re-mount并意识到这种变化。 它绑定到它内部创建的 属性 (inputValue) 并一直监视它,而不是从 parent 传递的 modelValue。 这是一个使用您的代码的 example,它完全按照预期的方式工作,并按照您的预期工作。 它接收一次值 (firstName.value),创建另一个 属性 (inputValue) 并在发生变化时发出该值。 不管parent改变firstName.value 属性多少次,child都不在乎,输入[=31=的不是属性 ]的child看。

你可以这样做

<template>
  <div class="form-group">
    <label :for="identifier"
      >{{ title }}
      <span class="text-danger" v-if="validation">*</span>
    </label>
    <input
      :id="identifier"
      :type="type"
      class="form-control"
      :class="validationMessageClass"
      :placeholder="title"
      v-model="localValue" // here we bind localValue as v-model to the input
    />
    <div class="invalid-feedback" v-if="validationMessage">
      {{ validationMessage }}
    </div>
  </div>
</template>

<script>
export default {
  ... // your code
  computed: {
    localValue: {
      get() {
        return this.modelValue;
      },
      set(value) {
        this.$emit("update:modelValue", value);
      },
    },
  },
};
</script>

我们删除了观察者,而是使用一个计算的 属性,它将 return 中的模型值 getter(所以每当 parent 传递一个新值时,我们实际上使用 that 而不是 localValue) 和 setter 将更新事件发送到 parent.

这是另一个 codesandbox 示例来说明上述解决方案。