未使用同步修改器更新计算对象

时间:2017-10-30 16:37:36

标签: vue.js vuejs2

我有一个只计算日期格式的计算属性:

computed: {
    items() { 
        return this.licenseItems.map(function(license) {
             license.expires_at = moment(license.expires_at).format('MM/DD/YYYY');
             return license;
        });
    }
}

我将licenseItems传递给带有.sync修饰符的表单组件,并从表单中发出update:field事件。在vue dev工具中,我可以看到licenseItems(数据)已正确更新,但items(已计算)仍显示旧数据,因此未执行重新计算。

我注意到如果我删除地图并从计算属性中返回licenseItems对象,则会更新它。使用同步修饰符时,Vue在映射对象上的计算属性是否存在问题?

1 个答案:

答案 0 :(得分:2)

您应该知道您正在修改计算中的基础对象。从你的小提琴:

  computed: {
    mapped: function() {
      return this.items.map(function(item) {
        let original = item.date;
        item.date = moment(item.date).format('MM/DD/YYYY');
        console.log(original + ' => ' + item.date);
        return item;
      });
    }
  }

您的incrementDates函数也会直接修改基础对象。

由于items的每个元素都是一个对象,item是对同一个对象的引用,因此您的例程会更新items本身的成员。如果您打算修改对象值,则应使用watch而不是computed。如果您想要一个不修改数据项的正确计算,则需要deep copy个对象。

在下面的示例中,您可以看到数据值和计算值是不同的,但计算结果基于数据。此外,update事件与sync一起使用以更新父级中的值,而不是直接在组件中更新的值。您可以输入Date了解的任何日期格式来设置值。

new Vue({
  el: '#app',
  data: {
    licenseItems: [{
      expires_at: Date.now()
    }]
  },
  computed: {
    items() {
      return this.licenseItems.map(function(license) {
        const newItem = Vue.util.extend({}, license);

        newItem.expires_at = moment(license.expires_at).format('MM/DD/YYYY');
        return newItem;
      });
    }
  },
  components: {
    myUpdater: {
      props: ['items'],
      methods: {
        doUpdate(event, index) {
          const newObj = this.items.map(item => Vue.util.extend({}, item));
          
          newObj[index].expires_at = new Date(event.target.value);
          console.log("new object", newObj);
          this.$emit('update:items', newObj);
        }
      }
    }
  }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.1/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
  <my-updater :items.sync="licenseItems" inline-template>
    <div>
      <input v-for="item, index in items" :value="item.expires_at" @change="doUpdate($event, index)">
    </div>
  </my-updater>
  <div v-for="item in items">
    {{item.expires_at}}
  </div>
</div>