1. ホーム
  2. javascript

[解決済み] Vue - オブジェクトの配列をディープウォッチして、変化を計算する?

2022-08-25 20:26:32

質問

という配列があります。 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.)

そして、その中にある を作ったコードペンは で、結果は空の配列であり、私が期待する変更されたオブジェクトではありません。

なぜこのようなことが起こるのか、どこで間違ってしまったのか、どなたか教えていただけると助かります。

どのように解決するのですか?

古い値と新しい値の比較関数に何らかの問題があるようです。あまり複雑にすると、後でデバッグの手間が増えるので、あまり複雑にしない方がよいでしょう。シンプルにするのがよいでしょう。

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

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

personコンポーネントの内部を見るための動作例を以下に示します。もし、親側で処理したい場合には $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/[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>