Javascript Vue.js-如何正确监视嵌套数据

Javascript Vue.js-如何正确监视嵌套数据,javascript,vue.js,vue-component,vue-resource,Javascript,Vue.js,Vue Component,Vue Resource,我试图理解如何正确地观察道具的变化。 我有一个父组件(.vue文件),它从ajax调用接收数据,将数据放入对象中,并使用它通过v-for指令呈现一些子组件,下面是我的实现的简化: <template> <div> <player v-for="(item, key, index) in players" :item="item" :index="index" :key="

我试图理解如何正确地观察道具的变化。 我有一个父组件(.vue文件),它从ajax调用接收数据,将数据放入对象中,并使用它通过v-for指令呈现一些子组件,下面是我的实现的简化:

<template>
    <div>
        <player v-for="(item, key, index) in players"
            :item="item"
            :index="index"
            :key="key"">
        </player>
    </div>
</template>
watch: {
  myVariable: {
     handler(newVal, oldVal){  // here having access to the new and old value
       // do stuff
     },
     deep: true,
     immediate: true //  Also very important the immediate in case you need it, the callback will be called immediately after the start of the observation

  }
}
项目对象如下所示:

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
获取新元素或现有元素中的某些变化时执行一些操作。如有任何建议,我们将不胜感激。

您可以使用:

watch: {
  item: {
     handler(val){
       // do stuff
     },
     deep: true
  }
}
现在,这将检测
数组中对象的任何更改以及数组本身的添加(与一起使用时)。下面是一个JSFIDLE:

编辑

如果您不想查看顶级对象上的每一个更改,只想使用一种不那么笨拙的语法直接查看嵌套对象,那么您可以只查看一个
计算的

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

下面是JSFIDLE:

另一个好方法,一个更优雅的方法如下:

 watch:{
     'item.someOtherProp': function (newVal, oldVal){
         //to work with changes in someOtherProp
     },
     'item.prop': function(newVal, oldVal){
         //to work with changes in prop
     }
 }
(我是从中的@peerbolte学到这个方法的)

如果你想看一段时间的财产,然后取消它

或查看库子组件属性

您可以使用“动态观察者”:

this.$watch(
 'object.property', //what you want to watch
 (newVal, oldVal) => {
    //execute your code here
 }
)
$watch
返回一个unwatch函数,如果调用该函数,该函数将停止监视

var unwatch = vm.$watch('a', cb)
// later, teardown the watcher
unwatch()
您还可以使用
deep
选项:

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

请务必查看

我对使用
deep:true
的公认答案的问题是,在深入观察数组时,我无法轻松识别数组中包含更改的元素。我找到的唯一清晰的解决方案是子对象中的VueJs deep watch

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

另一种补充的方法是,我曾经“破解”过这个解决方案: 我设置了一个单独的
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...
    }
}

这里没有提到,但是如果扩展
vue
类,也可以使用
vue属性装饰器
模式

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

export default class SomeClass extends Vue {
   ...

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

   ...
}
跟踪列表中单个已更改的项 如果要查看列表中的所有项目,并知道列表中的哪个项目发生了更改,可以分别为每个项目设置自定义观察者,如下所示:

var vm=new Vue({
数据:{
名单:[
{name:'要监视的对象'},
{name:'obj2要监视'},
],
},
方法:{
handleChange(新值、旧值){
//在这里处理更改!
//注意:对于变异对象,newVal和oldVal将是相同的。
console.log(newVal);
},
},
创建(){
this.list.forEach((val)=>{
this.$watch(()=>val,this.handleChange,{deep:true});
});
},
});
如果您的列表没有立即填充(如原始问题中),您可以将逻辑从创建的
移动到需要的任何位置,例如
.then()
块中

观察变化的列表 如果您的列表本身更新为有新的或删除的项目,我开发了一种有用的模式,“浅层”监视列表本身,并在列表更改时动态监视/取消跟踪项目:

//注意:此示例使用Lodash(u.differenceBy和u.pull)来比较列表
//并删除列表项。同样的结果也可以通过大量的实验来实现
//如果需要避免使用外部库,请使用list.indexOf(…)。
var vm=新的Vue({
数据:{
名单:[
{name:'要监视的对象'},
{name:'obj2要监视'},
],
watchTracker:[],
},
方法:{
handleChange(新值、旧值){
//在这里处理更改!
console.log(newVal);
},
更新跟踪程序(){
//用于将列表项与“watchTracker”进行比较的帮助函数。
const getItem=(val)=>val.item | val;
//尚未监视的项目:监视并添加到监视列表。
_.differenceBy(this.list,this.watchTracker,getItem).forEach((item)=>{
const unwatch=this.$watch(()=>item,this.handleChange,{deep:true});
this.watchTracker.push({item:item,unwatch:unwatch});
//如果向列表中添加新项目应视为“更改”,请取消下面的注释。
//本手册变更(项目);
});
//不再存在的项目:取消跟踪并从关注列表中删除。
_.differenceBy(this.watchTracker、this.list、getItem).forEach((watchObj)=>{
watchObj.unwatch();
_.拉动(此为.watchTracker,watchObj);
//(可选)在此处添加任何进一步的清理,以便在删除项目时进行清理。
});
},
},
观察:{
列表(){
返回此.updateWatchers();
},
},
创建(){
返回此.updateWatchers();
},
});

对我来说,没有一个答案是有效的。实际上,如果您希望监视嵌套数据,并且多次调用组件。因此,使用不同的道具来识别它们。
例如
我的解决方法是创建一个附加vuex状态变量,手动更新该变量以指向上次更新的属性

以下是Vuex.ts实现示例:

export default new Vuex.Store({
    state: {
        hovEpacTduList: {},  // a json of arrays to be shared by different components, 
                             // for example  hovEpacTduList["chart1"]=[2,6,9]
        hovEpacTduListChangeForChart: "chart1"  // to watch for latest update, 
                                                // here to access "chart1" update 
   },
   mutations: {
        setHovEpacTduList: (state, payload) => {
            state.hovEpacTduListChangeForChart = payload.chart // we will watch hovEpacTduListChangeForChart
            state.hovEpacTduList[payload.chart] = payload.list // instead of hovEpacTduList, which vuex cannot watch
        },
}
在任何组件函数上更新存储:

    const payload = {chart:"chart1", list: [4,6,3]}
    this.$store.commit('setHovEpacTduList', payload);
现在,在任何要获取更新的组件上:

    computed: {
        hovEpacTduListChangeForChart() {
            return this.$store.state.hovEpacTduListChangeForChart;
        }
    },
    watch: {
        hovEpacTduListChangeForChart(chart) {
            if (chart === this.chart)  // the component was created with chart as a prop <MyComponent chart="chart1"/> 
                console.log("Update! for", chart, this.$store.state.hovEpacTduList[chart]);
        },
    },
计算:{
hovEpacTduListChangeForChart(){
返回此。$store.state.hovEpacTduListChangeForChart;
}
},
观察:{
HOVEPACTDULIST更改图表(图表){
if(chart==this.chart)//组件是用chart作为道具创建的
log(“Update!for”,chart,this.$store.state.hovEpacTduList[chart]);
},
},

我发现它也是这样工作的:

watch: {
    "details.position"(newValue, oldValue) {
        console.log("changes here")
    }
},
data() {
    return {
      details: {
          position: ""
      }
    }
}
这里有一个方法
created() {
    this.$watch(
        () => JSON.stringify(this.object),
            (newValue, oldValue) => {
                //do your stuff                
            }
    );
},
watch: {
  myVariable: {
     handler(newVal, oldVal){  // here having access to the new and old value
       // do stuff
     },
     deep: true,
     immediate: true //  Also very important the immediate in case you need it, the callback will be called immediately after the start of the observation

  }
}