Vue - 深入观察一组对象并计算变化?

新手上路,请多包涵

我有一个名为 people 的数组,其中包含如下对象:

[
  {id: 0, name: 'Bob', age: 27},
  {id: 1, name: 'Frank', age: 32},
  {id: 2, name: 'Joe', age: 38}
]

它可以改变:

[
  {id: 0, name: 'Bob', age: 27},
  {id: 1, name: 'Frank', age: 33},
  {id: 2, name: 'Joe', age: 38}
]

注意弗兰克刚满 33 岁。

我有一个应用程序,我试图在其中查看人员数组,当任何值发生更改时,然后记录更改:

 <style>
input {
  display: block;
}
</style>

<div id="app">
  <input type="text" v-for="(person, index) in people" v-model="people[index].age" />
</div>

<script>
new Vue({
  el: '#app',
  data: {
    people: [
      {id: 0, name: 'Bob', age: 27},
      {id: 1, name: 'Frank', age: 32},
      {id: 2, name: 'Joe', age: 38}
    ]
  },
  watch: {
    people: {
      handler: function (val, oldVal) {
        // Return the object that changed
        var changed = val.filter( function( p, idx ) {
          return Object.keys(p).some( function( prop ) {
            return p[prop] !== oldVal[idx][prop];
          })
        })
        // Log it
        console.log(changed)
      },
      deep: true
    }
  }
})
</script>

我基于 昨天提出的关于数组比较的问题, 并选择了最快的工作答案。

因此,此时我希望看到以下结果: { id: 1, name: 'Frank', age: 33 }

但是我在控制台中得到的只是(记住我在一个组件中拥有它):

 [Vue warn]: Error in watcher "people"
(found in anonymous component - use the "name" option for better debugging messages.)

我制作的 codepen 中,结果是一个空数组,而不是我所期望的改变的对象。

如果有人能提出为什么会发生这种情况或我在这里出错的地方,那么将不胜感激,非常感谢!

原文由 Craig van Tonder 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 356
2 个回答

您在旧值和新值之间的比较函数有一些问题。最好不要把事情复杂化,因为这会增加你以后的调试工作。你应该保持简单。

最好的方法是创建一个 person-component 并在自己的组件中分别观察每个人,如下所示:

 <person-component :person="person" v-for="person in people"></person-component>

请在下面找到一个用于观看内部人员组件的工作示例。如果你想在父端处理它,你可以使用 $emit 向上发送一个事件,包含 id 被修改的人。

 Vue.component('person-component', {
    props: ["person"],
    template: `
        <div class="person">
            {{person.name}}
            <input type='text' v-model='person.age'/>
        </div>`,
    watch: {
        person: {
            handler: function(newValue) {
                console.log("Person with ID:" + newValue.id + " modified")
                console.log("New age: " + newValue.age)
            },
            deep: true
        }
    }
});

new Vue({
    el: '#app',
    data: {
        people: [
          {id: 0, name: 'Bob', age: 27},
          {id: 1, name: 'Frank', age: 32},
          {id: 2, name: 'Joe', age: 38}
        ]
    }
});
 <script src="https://unpkg.com/vue@2.1.5/dist/vue.js"></script>
<body>
    <div id="app">
        <p>List of people:</p>
        <person-component :person="person" v-for="person in people"></person-component>
    </div>
</body>

原文由 Mani 发布,翻译遵循 CC BY-SA 3.0 许可协议

我已经更改了它的实现以解决您的问题,我创建了一个对象来跟踪旧更改并将其与之进行比较。您可以使用它来解决您的问题。

在这里,我创建了一个方法,其中旧值将存储在一个单独的变量中,然后将在手表中使用。

 new Vue({
  methods: {
    setValue: function() {
      this.$data.oldPeople = _.cloneDeep(this.$data.people);
    },
  },
  mounted() {
    this.setValue();
  },
  el: '#app',
  data: {
    people: [
      {id: 0, name: 'Bob', age: 27},
      {id: 1, name: 'Frank', age: 32},
      {id: 2, name: 'Joe', age: 38}
    ],
    oldPeople: []
  },
  watch: {
    people: {
      handler: function (after, before) {
        // Return the object that changed
        var vm = this;
        let changed = after.filter( function( p, idx ) {
          return Object.keys(p).some( function( prop ) {
            return p[prop] !== vm.$data.oldPeople[idx][prop];
          })
        })
        // Log it
        vm.setValue();
        console.log(changed)
      },
      deep: true,
    }
  }
})

查看更新的 代码笔

原文由 Viplock 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题