Подтвердить что ты не робот

Vue.js - Как правильно следить за вложенными данными

Я пытаюсь понять, как правильно следить за некоторыми вариантами поддержки. У меня есть родительский компонент (.vue файлы), который получает данные от вызова ajax, помещает данные внутри объекта и использует его для рендеринга некоторого дочернего компонента через директиву v-for, ниже упрощения моей реализации:

<template>
    <div>
        <player v-for="(item, key, index) in players"
            :item="item"
            :index="index"
            :key="key"">
        </player>
    </div>
</template>

... затем внутри <script>:

 data(){
     return {
         players: {}
 },
 created(){
        let self = this;
        this.$http.get('../serv/config/player.php').then((response) => {
            let pls = response.body;
            for (let p in pls) {
                self.$set(self.players, p, pls[p]);
            }
    });
}

объекты объекта:

item:{
   prop: value,
   someOtherProp: {
       nestedProp: nestedValue,
       myArray: [{type: "a", num: 1},{type: "b" num: 6} ...]
    },
}

Теперь, внутри моего дочернего компонента "плейер", я пытаюсь наблюдать за изменением свойства элемента и использую:

...
watch:{
    'item.someOtherProp'(newVal){
        //to work with changes in "myArray"
    },
    'item.prop'(newVal){
        //to work with changes in prop
    }
}

Это работает, но мне кажется немного сложнее, и мне было интересно, правильно ли это сделать. Моя цель состоит в том, чтобы выполнять некоторые действия каждый раз, когда изменяется prop или myArray получает новые элементы или некоторые изменения внутри существующих. Любое предложение будет оценено по достоинству.

4b9b3361

Ответ 1

Вы можете использовать для этого глубокий наблюдатель:

watch: {
  item: {
     handler(val){
       // do stuff
     },
     deep: true
  }
}

Теперь будут обнаружены какие-либо изменения объектов в массиве item и дополнения к самому массиву (при использовании с Vue.set). Здесь JSFiddle: http://jsfiddle.net/je2rw3rs/

РЕДАКТИРОВАТЬ

Если вы не хотите следить за каждым изменением объекта верхнего уровня и просто хотите менее неудобный синтаксис для непосредственного просмотра вложенных объектов, вы можете просто посмотреть computed вместо этого:

var vm = new Vue({
  el: '#app',
  computed: {
    foo() {
      return this.item.foo;
    }
  },
  watch: {
    foo() {
      console.log('Foo Changed!');
    }
  },
  data: {
    item: {
      foo: 'foo'
    }
  }
})

Здесь JSFiddle: http://jsfiddle.net/oa07r5fw/

Ответ 2

Другим хорошим подходом и чуть более элегантным является следующее:

 watch:{
     'item.someOtherProp': function (newVal, oldVal){
         //to work with changes in someOtherProp
     },
     'item.prop': function(newVal, oldVal){
         //to work with changes in prop
     }
 }

(Я понял этот подход из @peerbolte в комментарии здесь)

Ответ 3

Еще один метод.

Не используйте функцию стрелки при этом. Вы не можете получить доступ к этому объекту.

watch:{
    'item.someOtherProp': function(newValue, oldValue){
        // Process
    }
}

Ответ 4

Как, если вы хотите некоторое время посмотреть недвижимость, а затем, чтобы ее посмотреть?

Или посмотреть свойство дочернего компонента библиотеки?

Вы можете использовать "динамический наблюдатель":

this.$watch(
 'object.property', //what you want to watch
 (newVal, oldVal) => {
    //execute your code here
 }
)

$watch возвращает функцию выключения, которая перестанет смотреть, если она вызвана.

var unwatch = vm.$watch('a', cb)
// later, teardown the watcher
unwatch()

Также вы можете использовать deep опцию:

this.$watch(
'someObject', () => {
    //execute your code here
},
{ deep: true }
)

Обязательно ознакомьтесь с документами.

Ответ 5

Моя проблема с принятым ответом использования deep: true заключается в том, что при глубоком просмотре массива я не могу легко определить, какой элемент массива содержит изменение. Единственное ясное решение, которое я нашел, - это ответ, который объясняет, как создать компонент, чтобы вы могли наблюдать за каждым элементом массива индивидуально.

Ответ 6

VueJs глубоко следит за дочерними объектами

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

Ответ 7

Еще один способ добавить, что я использовал для "взлома" этого решения, было сделать следующее: я установил отдельное computed значение, которое просто возвращало бы значение вложенного объекта.

data : function(){
    return {
        my_object : {
            my_deep_object : {
                my_value : "hello world";
            }.
        },
    };
},
computed : {
    helper_name : function(){
        return this.my_object.my_deep_object.my_value;
    },
},
watch : {
    helper_name : function(newVal, oldVal){
        // do this...
    }
}

Ответ 8

Я не вижу здесь упомянутого, но также можно использовать шаблон vue-property-decorator, если вы расширяете свой класс Vue.

import { Watch, Vue } from 'vue-property-decorator';

export default class SomeClass extends Vue {
   ...

   @Watch('item.someOtherProp')
   someOtherPropChange(newVal, oldVal) {
      // do something
   }

   ...
}