簡體   English   中英

Vue - 深入觀察一組對象並計算變化?

[英]Vue - Deep watching an array of objects and calculating the change?

我有一個名為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 中,結果是一個空數組,而不是我所期望的改變的對象。

如果有人能提出為什么會發生這種情況或我在這里出錯的地方,那么將不勝感激,非常感謝!

您在舊值和新值之間的比較函數有一些問題。 最好不要把事情復雜化,因為這會增加你以后的調試工作。 你應該保持簡單。

最好的方法是創建一個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>

這是定義明確的行為。 您無法獲取變異對象的舊值。 那是因為newValoldVal引用同一個對象。 Vue不會保留您變異的對象的舊副本。

如果你用另一個對象替換了這個對象,Vue 會為你提供正確的引用。

閱讀文檔中的Note部分。 ( vm.$watch )

更多關於這里這里

我已經更改了它的實現以解決您的問題,我創建了一個對象來跟蹤舊更改並將其與之進行比較。 您可以使用它來解決您的問題。

在這里,我創建了一個方法,其中舊值將存儲在一個單獨的變量中,然后將在手表中使用。

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

查看更新的代碼筆

組件方案和深度克隆方案各有優勢,但也存在問題:

  1. 有時您想跟蹤抽象數據的變化——圍繞該數據構建組件並不總是有意義的。

  2. 每次進行更改時深度克隆整個數據結構可能會非常昂貴。

我認為有更好的方法。 如果您想查看列表中的所有項目並知道列表中的哪個項目發生了變化,您可以分別在每個項目上設置自定義觀察者,如下所示:

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()將接收已更改的特定列表項 - 從那里您可以進行任何您喜歡的處理。

我還在這里記錄了一個更復雜的場景,以防您在列表中添加/刪除項目(而不是僅僅操作已經存在的項目)。

這就是我用來深入觀察物體的方法。 我的要求是觀察對象的子字段。

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

如果我們有對象或對象數組,並且我們想在 Vuejs 或 NUXTJS 中觀看它們,則需要在 watch 中使用deep: true

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

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

而不是“看”,我用“計算”​​解決了這個問題!

我沒有測試過這段代碼,但我認為它應該可以工作。 如果沒有,請在評論中告訴我。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM