为什么在使用NumericTextField时会出现“避免直接更改道具”的提示?

时间:2019-03-18 06:27:37

标签: vue.js vuex vuetify.js

我已经在VueJS中创建了一个简单的视图组件,并且遇到了一个非常常见的错误:

  

避免直接更改道具,因为该值将被覆盖   每当父组件重新渲染时。而是使用数据或   根据属性值计算属性。道具被突变:   “值”

这是我的代码:

<template>
    <numeric-text-field class="mx-auto" label="Head Mass" units="kg" v-model="turbine.head_mass" />
</template>

<script>
import NumericTextField from '@/components/common/NumericTextField'
export default {
  name: 'Turbines',
  components: {
    NumericTextField
  },
  data () {
    return {
      turbine: {}
    }
  }
}
</script>

<style scoped>
</style>

奇怪的是,我收到修改“值”的错误,但我的代码中没有值。我认为这是由数字文本字段创建的间接层引起的。当我仅使用普通输入文本时,此问题在我的代码中不存在。这里发生了什么?除了v-model,我还有其他特殊方法可以将模型连接到我的数字文本字段吗?

2 个答案:

答案 0 :(得分:0)

了解道具在Vue中的工作方式非常重要。这里的关键方面是one-way data flow使用道具。如果希望它是双向数据流,则需要使用v-model

话虽如此,您可以通过几种不同的方式进行此操作。我更喜欢将computed properties用于这样的事情!它很干净,并且易于遵循代码。

您应该在numeric-text-field组件中而不是直接修改道具,而应在 值已更改。这就是您的Turbines.vue的外观:

<template>
    <numeric-text-field class="mx-auto"
    label="Head Mass"
    units="kg"
    :headMass="turbine.head_mass"
    v-on:updateHeadMass="updateHeadMass"/>
</template>

<script>
import NumericTextField from '@/components/common/NumericTextField'
export default {
  name: 'Turbines',
  components: {
    NumericTextField
  },
  data () {
    return {
      // You should consider initializing your data with the structure that matches what you expect, instead of an empty object
      turbine: {
        head_mass: ""
      }
    }
  },
  methods: {
    updateHeadMass(value) {
      this.turbines.head_mass = value;
    }
  }
}
</script>

<style scoped>
</style>

您会注意到v-on:updateHeadMass属性。这就是我们侦听子组件发出的事件的方式。发出updateHeadMass偶数后,我们可以调用一个特定的函数并相应地更新父组件中的数据。这将导致子组件发生反应性更改,然后进行更新。

内部NumericTextField

使用一个计算属性,而不是直接修改道具,当输入更改时,该属性会发出事件,直到父组件为止 NumericTextField组件的外观如下:

<template>
  <div>
    <label for="headMass">Head Mass</label>
    <input type="text" v-model="localHeadMass"  name="headMass"/>
  </div>
</template>

<script>
export default {
  name: "numeric-text-field",
  computed: {
    localHeadMass: {
      get() {
        return this.headMass;
      },
      set(value) {
        // Now, anytime we change this property, our parent receives the new value and updates the `headMass` prop!
        this.$emit("updateHeadMass", value);
      }
    }
  },
  props: {
    headMass: {
      type: String,
      default: "0",
      required: true
    }
  }
};
</script>

<style scoped>
</style>

如果您不喜欢上述方法,可以改用这样的观察器:

<template>
  <div>
    <label for="headMass">Head Mass</label>
    <input type="text" v-model="localHeadMass" v-on:change="updateHeadMass" name="headMass"/>
  </div>
</template>

<script>
export default {
  name: "numeric-text-field",
  data: () => {
    return {
      localHeadMass: ""
    };
  },
  props: {
    headMass: {
      type: String,
      default: "0",
      required: true
    }
  },
  methods: {
    updateHeadMass() {
      this.$emit("updateHeadMass", this.localHeadMass);
    }
  },
  watch: {
    headMass(value) {
      this.localHeadMass = value;
    }
  }
};
</script>

<style scoped>
</style>

答案 1 :(得分:0)

在原始发布时,这对我来说并不为人所知,并在NumericTextField中发布。我以为这是标准的Vueify组件,但是是由同事添加的。如原始帖子的评论所指出的那样,它无法正确处理双向输入。

技巧是像Ohgodwhy建议的那样,从@input的NumericTextField组件中添加this。$ emit('input',value)。