Vue.js 更新的属性不会在子组件上更改
Posted
技术标签:
【中文标题】Vue.js 更新的属性不会在子组件上更改【英文标题】:Vue.js updated property doesn't change on child component 【发布时间】:2020-12-19 20:33:24 【问题描述】:我有一个子组件,它是一个 html 输入元素。它看起来像这样:
<label-input inputId="formProductId"
inputType="number"
inputName="productId"
:inputEnabled="filters.productId.options"
:label="translations['product_id']"
:placeholder="translations['product_id']"
:data="filters.productId.value"
/>
LabelInput.vue 文件:
<template>
<div class="form-element">
<label :for="inputId" :class="['form-element-title', 'js-focused': focused ]"> label </label>
<input @input="updateValue($event.target.value)" :type="inputType" :id="inputId" :name="inputEnabled ? inputName : false" v-model="inputData" :placeholder="placeholder" @focus="focused = true" @blur="focused = false">
</div>
</template>
<script lang="ts">
import Component, Prop, Vue from 'vue-property-decorator';
@Component
export default class LabelInput extends Vue
@Prop( default: () => '' ) inputId!: string
@Prop( default: () => '' ) inputType!: string
@Prop( default: () => '' ) inputName!: string
@Prop( default: () => '' ) label!: string
@Prop( default: () => '' ) placeholder!: string
@Prop( default: () => ) data!: []
@Prop( default: () => true ) inputEnabled!: string
private inputData = this.data
private focused = false
updateValue (value: string)
this.$root.$emit('input', 'inputName' : this.inputName, 'inputValue' : value);
所以模型通过filters.productId.value作为数据传递,然后变成局部变量inputData。
现在,如果我更改输入值,我会使用 updateValue 函数,该函数会发出输入名称并将其值返回到父组件,从而更新原始 filters.productId.value 值。这很好用。
现在的问题是我的父组件上有一个函数,它将 filters.productId.value 值重置回 null。它看起来像这样:
clearFilters()
for (const [key, value] of Object.entries(this.filters))
this.filters[key].value = null;
现在我的子组件 LabelInput 中的数据没有改变,即使 filters.productId.value 现在为空。如何刷新子组件?
【问题讨论】:
看来这个问题是由this.data
没有同步到this.inputData
父组件更改the props=data
引起的。所以一种解决方案是为this.data
添加一只手表,当它的值改变时,让this.inputData=this.data
在你的LabelInput.vue
中
但是 LabelInput 组件不知道数据何时更改。我怎么知道什么时候应该设置它?
【参考方案1】:
我还没有将 Vue 用作类组件,但似乎问题在于将 prop 设置为类中的属性。
private inputData = this.data
Vue 监听 prop 变化,但是 data 不监听引用的变化,所以 prop 发生了变化,但 inputData
没有变化,因为 Vue 没有为它设置监听器。
当我想做与您类似的事情时,我使用computed
属性。查看docs 看看它是如何实现的。
使用计算属性。
get inputData()
return this.data;
我相信这会如您所愿。
为了更好地可视化我们在 cmets 中所说的内容,下面是没有 v-model 的代码的样子。
输入:
<input :value="inputData" @input="updateValue($event.target.value)" :type="inputType" :id="inputId" :name="inputEnabled ? inputName : false" :placeholder="placeholder" @focus="focused = true" @blur="focused = false">
吸气剂:
get inputData()
// you can change your prop here and return a new value.
// A lower or upper case, for example. Just don't change the prop, only use it.
return this.data;
更新值:
updateValue(value)
this.$root.$emit('input', 'inputName' : this.inputName, 'inputValue' : value);
另外,我认为不需要使用$root
,因为您可以在组件中使用$emit
。对于非类组件你通过this.$emit
访问,我相信这里应该是一样的。
你可以做的另一个改变是在 html 中监听事件:
<label-input inputId="formProductId"
inputType="number"
inputName="productId"
:inputEnabled="filters.productId.options"
:label="translations['product_id']"
:placeholder="translations['product_id']"
:data="filters.productId.value"
@updateValue="doSomething"
/>
您可以声明一个名为doSomething
的方法,它将接收到的值作为第一个参数,或者简单地将变量设置为事件@updateValue="(value) => filters.productId.value = value"
接收到的值。这也可以。
【讨论】:
很好,它现在看起来可以工作了。但是二传手呢?它应该是什么样子?我无法设置 this.data 它,因为我收到有关直接改变属性的警告。还是我应该将设置器留空? 您可以使用set inputData() // emit the event to parent component here
。 Here 描述得很好。
我看到您正在使用 v-model 和 @input,我认为没有必要同时使用它们。我相信您可以仅将 v-model 与 getter 和 setter 一起使用,并在 setter 内发出事件。
另一种选择是使用:value=inputData
和@input
事件而不使用v-model
。这不会触发有关直接改变属性的警告。这就是我通常使用输入处理组件内部数据的方式,并且效果惊人。很清楚,子组件的工作只是接收用户输入的数据并将其发送给负责的(在本例中为父)组件。
是的,您需要使用 emit 两种方式将数据发送到父组件。您的输入应如下所示:<input :value="inputData" @input="updateValue(...)">
,您的方法:get inputName() return this.data updateValue(val) // emit here
。这样,您的子组件从父组件接收数据并显示它,然后您的 updateValue 将其发送给父组件,父组件再次将值发送给子组件。这样孩子接收到的数据来显示它并且不会改变它。只有在父组件中需要设置filters.productId.value=value
才能更改数据。以上是关于Vue.js 更新的属性不会在子组件上更改的主要内容,如果未能解决你的问题,请参考以下文章
Vue.js - 如何将 prop 作为 json 数组传递并在子组件中正确使用?