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
получает новые элементы или некоторые изменения внутри существующих. Любое предложение будет оценено по достоинству.
Ответы
Ответ 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
}
...
}