web-dev-qa-db-ja.com

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}
]

Frankがちょうど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.)

そして 私が作ったcodepen では、結果は空の配列であり、変更された変更されたオブジェクトではありません。

なぜこれが起こっているのか、ここで私が間違っていたのか誰かが示唆できたら、それは大いに感謝されるでしょう、どうもありがとう!

74

古い値と新しい値の比較機能に問題があります。後でデバッグ作業が増えるので、それほど複雑にしないことをお勧めします。あなたはそれを単純にしておくべきです。

以下のように、最良の方法はperson-componentを作成し、それ自身のコンポーネント内ですべての人を個別に監視することです。

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

内部の人のコンポーネントを見るための実用的な例を以下に見つけてください。もしあなたが親の側でそれを処理したいのならば、あなたはidを含むイベントを上向きに送るために$emitを使うことができます。

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/[email protected]/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>
94
Mani

私はあなたの問題を解決するためにそれの実装を変更しました、私は古い変更を追跡しそれとそれを比較するためにオブジェクトを作りました。あなたはあなたの問題を解決するためにそれを使うことができます。

ここでは、古い値を別の変数に格納してウォッチで使用する方法を作成しました。

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 を参照してください。

17
Viplock

明確に定義された動作です。mutatedオブジェクトの古い値を取得することはできません。これは、newValoldValの両方が同じオブジェクトを参照しているためです。 Vueはnot変更したオブジェクトの古いコピーを保存します。

オブジェクトを別のオブジェクトに置き換えた場合、Vueは正しい参照をあなたに提供していたでしょう。

ドキュメントのNoteセクションを読んでください。 (vm.$watch

詳しくは こちらこちら をご覧ください。

14
Quirk

これは私が物を深く見るために使うものです。私の要求はオブジェクトの子フィールドを監視することでした。

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