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

fafcakar  于 2023-02-13  发布在  Vue.js
关注(0)|答案(7)|浏览(144)

我有一个名为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>

我基于question that I asked yesterday中关于数组比较的内容,选择了最快的工作答案。
因此,在这一点上,我希望看到以下结果:{ 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 that I made中,结果是一个空数组,而不是我所期望的更改对象。
如果任何人可以建议为什么会发生这种情况或我在这里出了问题,那么它将是非常感谢,非常感谢!

tsm1rwdh

tsm1rwdh1#

你的新旧值比较函数有问题。最好不要把事情弄得太复杂,因为这会增加你以后的调试工作量。你应该保持简单。
最好的方法是创建一个person-component,并在它自己的组件中分别观察每个人,如下所示:

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

下面是一个观察内部人员组件的工作示例。如果您想在父端处理它,可以使用$emit向上发送一个事件,包含修改人员的id
x一个一个一个一个x一个一个二个x

ymdaylpp

ymdaylpp2#

我已经改变了它的实现来解决你的问题,我做了一个对象来跟踪旧的变化并与之比较,你可以用它来解决你的问题。
这里我创建了一个方法,其中旧值将存储在一个单独的变量和中,然后将在手表中使用。

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

请参阅更新的codepen

zdwk9cvp

zdwk9cvp3#

这是一个定义良好的行为。你不能得到一个 mutated 对象的旧值。这是因为newValoldVal引用了同一个对象。Vue将 * 不会 * 保留一个你mutated的对象的旧副本。
如果您用另一个对象“替换”了该对象,Vue将为您提供正确的引用。
阅读文档中的Note部分。(vm.$watch
有关herehere的更多信息。

3j86kqsm

3j86kqsm4#

组件解决方案和深度克隆解决方案各有优势,但也存在问题:
1.有时候,您需要跟踪抽象数据中的更改-围绕这些数据构建组件并不总是有意义的。
1.每次进行更改时深度克隆整个数据结构可能会非常昂贵。
我认为有一个更好的方法,如果你想观察列表中的所有项目,并知道列表中的哪个项目发生了变化,你可以分别为每个项目设置自定义观察器,如下所示:

var vm = new Vue({
  data: {
    list: [
      {name: 'obj1 to watch'},
      {name: 'obj2 to watch'},
    ],
  },
  methods: {
    handleChange (newVal) {
      // Handle changes here!
      console.log(newVal);
    },
  },
  created () {
    this.list.forEach((val) => {
      this.$watch(() => val, this.handleChange, {deep: true});
    });
  },
});

使用这个结构,handleChange()将接收更改的特定列表项-从那里您可以执行任何您喜欢的处理。
我还编写了一个more complex scenario here文档,以防您向列表添加/删除项目(而不仅仅是操作已经存在的项目)。

zlwx9yxi

zlwx9yxi5#

这是我用来深度观察对象的工具,我的要求是观察对象的子字段。

new Vue({
    el: "#myElement",
    data:{
        entity: {
            properties: []
        }
    },
    watch:{
        'entity.properties': {
            handler: function (after, before) {
                // Changes detected.    
            },
            deep: true
        }
    }
});
z31licg0

z31licg06#

如果我们有对象或对象数组,并希望在Vuejs或NUXTJS中查看它们,则需要在watch中使用deep: true

watch: {
      'Object.key': {
         handler (val) {
             console.log(val)
         },
         deep: true
       } 
     }

     watch: {
      array: {
         handler (val) {
             console.log(val)
         },
         deep: true
       } 
     }
zvms9eto

zvms9eto7#

我用“计算”代替“观察”解决了这个问题!
我还没有测试过这段代码,但我认为它应该可以工作。如果没有,请在评论中告诉我。

<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}
    ],
    oldVal: {},
    peopleComputed: computed({
      get(){
        this.$data.oldVal = { ...people };
        return people;
      },
      set(val){
        // Return the object that changed
        var changed = val.filter( function( p, idx ) {
          return Object.keys(p).some( function( prop ) {
            return p[prop] !== this.$data.oldVal[idx][prop];
          })
        })
        // Log it
        console.log(changed)
        this.$data.people = val;
      }
    }),
  }
})
</script>

相关问题