【问题标题】:Avoid mutating a prop directly in VueJS 2避免在 VueJS 2 中直接改变 prop
【发布时间】:2017-07-25 15:37:22
【问题描述】:

首先,我刚开始玩 VueJS,所以这不可能是 VueJS 版本的东西,正如建议的 here

它可能是重复的:

我的问题始于我的 Html 看起来像这样:

<div id="app">
  <div class="row">
    <div class="form-group col-md-8 col-md-offset-2">
      <birthday-controls
       :birthDay="birthDay"
       :birthMonth="birthMonth"
       :birthYear="birthYear">
      </birthday-controls>
    </div>
  </div>
</div>

和 JS:

Vue.component('birthday-controls', {

    template: `<div class="birthday">
    <input type="text" name="year"  placeholder="yyyy" v-model="birthYear" size="4" maxlength="4"/>
    <input type="text" name="month" placeholder="mm" v-show="validYear" v-model="birthMonth" size="3" maxlength="2"/>
    <input type="text" v-show="validYear && validMonth" name="day" placeholder="dd" v-model="birthDay" size="2" maxlength="2"/>
  </div>`,

    props: ['birthDay', 'birthMonth', 'birthYear'],

    computed: {
        validYear: function() {
            return (this.birthYear > new Date().getFullYear()-100 && this.birthYear < new Date().getFullYear()-14)
        },
        validMonth: function() {
            return (this.birthMonth > 0 && this.birthMonth <= 12)
        },
        validDay: function() {
            return (this.birthDay > 0 && this.birthDay <=31) //I have to add more checking here for february, leap years and ....
        }
    }

});

new Vue({
    el: '#app',

    data: function() {
        return {
            birthDay: "",
            birthMonth: "",
            birthYear: ""
        }
    },

});

我这里准备了codepen:http://codepen.io/AngelinCalu/pen/OpXBay

但是,这里的第二个答案:vuejs update parent data from child component 让我意识到我错过了一些东西

在该示例中,它在其中一个方法中设置了一个this.$emit('increment'),并在特定事件上触发它。

在另一个示例中:Update a child's data component to the father component in vue.js using .vue webpack(vue2),答案建议添加 watch 以发出更改。

  watch: {
    val() {
      this.$emit('title-updated', this.val);
    }
  }

现在我更困惑了!处理这个问题的正确(或最佳)方法是什么?

注意: 如果我从最初的 html 中删除:

   :birthDay="birthDay"
   :birthMonth="birthMonth"
   :birthYear="birthYear"

它仍然按预期工作,但我仍然收到 Vue 警告,但是,如果我按照此处的方法:https://stackoverflow.com/a/41901150/2012740,它会停止工作,但我没有收到任何错误。

我的更新代码:https://jsfiddle.net/angelin8r/647m7vdf/

总结:我从一开始就需要该功能,但没有[Vue warn]

这是我在最初的示例中得到的:

[Vue 警告]:避免直接改变 prop,因为每当父组件重新渲染时,该值都会被覆盖。相反,使用基于道具值的数据或计算属性。正在变异的道具:“birthYear”

【问题讨论】:

  • 是否需要在组件外部更改birthYear、birthMonth 或birthDay?比如,当它在组件中发生变化时,组件之外的东西知道吗?
  • 其实我只需要在组件内部改一下就可以了。可能我会以某种方式将它们存储到数据库中 birthday-controls 组件中。

标签: javascript vuejs2


【解决方案1】:

警告是将v-model 设置为属性值的结果。原因是如果您在组件外部更改birthYear、birthMonth或birthDay,那么无论当前内部的值如何,组件都会立即被覆盖。

相反,捕获一个副本。

Vue.component('birthday-controls', {

    template: `<div class="birthday">
    <input type="text" name="year"  placeholder="yyyy" v-model="internalBirthYear" size="4" maxlength="4"/>
    <input type="text" name="month" placeholder="mm" v-show="validYear" v-model="internalBirthMonth" size="3" maxlength="2"/>
    <input type="text" v-show="validYear && validMonth" name="day" placeholder="dd" v-model="internalBirthDay" size="2" maxlength="2"/>
  </div>`,

    props: ['birthDay', 'birthMonth', 'birthYear'],

    data(){
      return {
        internalBirthDay: this.birthDay,
        internalBirthMonth: this.birthMonth, 
        internalBirthYear: this.birthYear
      }
    },

    computed: {
        validYear: function() {
            return (this.internalBirthYear > new Date().getFullYear()-100 && this.internalBirthYear < new Date().getFullYear()-14)
        },
        validMonth: function() {
            return (this.internalBirthMonth > 0 && this.internalBirthMonth <= 12)
        },
        validDay: function() {
            return (this.internalBirthDay > 0 && this.internalBirthDay <=31) //I have to add more checking here for february, leap years and ....
        }
    }

});

你几乎完全在你的小提琴中做了这件事,但你没有更正你的计算值。

computed: {
    validYear: function() {
        return (this.birthYear > new Date().getFullYear()-100 && this.birthYear < new Date().getFullYear()-14)
    },
    validMonth: function() {
        return (this.birthMonth > 0 && this.birthMonth <= 12)
    },
    validDay: function() {
        return (this.birthDay > 0 && this.birthDay <=31) //I have to add more checking here for february, leap years and stuff
    }
},

应该是

computed: {
    validYear: function() {
        return (this.var_birthYear > new Date().getFullYear()-100 && this.var_birthYear < new Date().getFullYear()-14)
    },
    validMonth: function() {
        return (this.var_birthMonth > 0 && this.var_birthMonth <= 12)
    },
    validDay: function() {
        return (this.var_birthDay > 0 && this.var_birthDay <=31) //I have to add more checking here for february, leap years and stuff
    }
},

【讨论】:

  • 这与我尝试过的有什么不同?我只是以不同的方式命名变量。
  • @AngelinCalu 我不知道他们最初来自哪里。如果您只在组件中设置并保存它们,我想没有理由将它们传递进去。
  • 警告的原因是birthDay是一个道具。因为birthDay 是一个prop,它可以从组件的外部改变。这意味着您在组件内部所做的任何事情都可以被覆盖。如果将birthDay 从 props 移到 data 中,并且根本不使用 props,那么将其命名为birthDay 或 var_birthDay 都没有关系。仅当您还拥有birthDay 作为道具时才引入 var_birthDay。
  • @AngelinCalu 看看这支笔。第一个组件,如果更改文本并单击按钮,文本将保持不变。第二个组件,如果更改文本并单击按钮,文本将被覆盖,因为它使用了一个道具。 codepen.io/Kradek/pen/KWMjbx?editors=1011
  • 道具是单向的。 vueMessage 是在父级中定义的,所以它不会改变(对于任何原始值)。这就是 $emit 的用武之地。如果您想根据孩子中的某些内容更改父级,则需要 $emit 一个事件并在父级中处理它。将 prop 视为 javascript 中函数的参数。你可以传入它,你可以在你的函数内部改变它,但它不会在你的函数之外改变。
猜你喜欢
  • 1970-01-01
  • 2020-09-11
  • 2020-09-24
  • 2021-06-18
  • 2020-06-23
  • 2019-10-24
  • 2020-08-27
  • 2019-02-07
  • 2018-08-25
相关资源
最近更新 更多