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

2022-08-30 04:40:18

我有一个名为数组,其中包含如下对象: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岁。

我有一个应用程序,我正在尝试观察people数组,当任何值更改时,然后记录更改:

<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.)

在我制作的代码笔中,结果是一个空数组,而不是更改的已更改对象,这将是我所期望的。

如果有人能建议为什么会发生这种情况,或者我在这里哪里出错了,那么将不胜感激,非常感谢!


答案 1

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

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

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

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

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>

答案 2

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

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

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,
    }
  }
})

查看更新的代码笔