2017-08-07 53 views
1

我的根目录中有两个对象 - objnewObj。我在deep: true上观察我的obj对象上的更改,并在更改时相应地更新newObj。Vue - 组件道具不能正确观察对象的变化

在我的vue调试器中,newObj似乎按预期更新,但该组件不执行for循环计数。或者如果我尝试{{ newObj }},它只记录第一次更新。

我试图重新创建问题on this Fiddle

我的html:

<div id="app"> 
    <button @click="appendTo">Append</button> 
    <my-comp v-bind:new-obj="newObj"></my-comp> 
</div> 

和VUE:

new Vue({ 
    el: '#app', 
    data: { 
    obj: {}, 
    newObj: {} 
    }, 

    methods: { 
    appendTo() { 
     if (typeof this.obj[1] === 'undefined') { 
     this.$set(this.obj, 1, {}) 
     } 

     var randLetter = String.fromCharCode(Math.floor(Math.random() * (122 - 97)) + 97); 
     this.$set(this.obj[1], randLetter, [ [] ]) 
     } 
    }, 

    watch: { 
    obj: { 
     handler(obj) { 
     var oldKeys = Object.keys(obj) 
     var newKeys = Object.keys(this.newObj); 

     var removedIndex = newKeys.filter(x => oldKeys.indexOf(x) < 0); 
     for (var i = 0, len = removedIndex.length; i < len; i++) { 
      delete this.newObj[removedIndex[i]] 
     } 

     oldKeys.map((key) => { 
      if (this.newObj.hasOwnProperty(key)) { 
      var newInnerKeys = Object.keys(this.newObj[key]); 
      var oldInnerKeys = Object.keys(obj[key]); 

      var additions = oldInnerKeys.filter(x => newInnerKeys.indexOf(x) < 0); 

      for (var i = 0, len = additions.length; i < len; i++) { 
       // here 
       this.$set(this.newObj[key], additions[i], [ [] ]); 
      } 

      var deletions = newInnerKeys.filter(x => oldInnerKeys.indexOf(x) < 0); 
      for (var i = 0, len = deletions.length; i < len; i++) { 
       delete this.newObj[key][deletions[i]] 
      } 

      } else { 
      this.newObj[key] = {} 
      for (var innerKey in obj[key]) { 
       this.$set(this.newObj, key, { 
       [innerKey]: [ [] ] 
       }); 
      } 
      } 

      console.log(obj); 
      console.log(this.newObj) 
     }); 
     }, 
     deep: true 
    } 
    } 
}) 

Vue.component('my-comp', { 
    props: ['newObj'], 
    template: ` 
     <div> 
     <div v-for="item in newObj"> 
      test 
     </div> 
    </div> 
    ` 
}) 
+0

可以尝试更新照片直接'this.newObj'而不是内部'this.newObj'键。您可以在最后使用'this.newObj = JSON.parse(JSON.stringify(this.newObject))'作弊。 'deep:true'申请obj不适用于newObj,所以如果参考未更新,UI不会更新 – Epitouille

+0

但是,如何才能够附加到现有密钥值?难道它只是覆盖现有的价值,并只保留这个项目?我会很感激任何指导 – senty

+0

你可以附加到现有的键值,但你需要告诉vuejs你的对象已经改变,它应该重新渲染。 Vuejs默认情况下,只监视newObj的引用,这意味着如果你改变这个对象:this.newObj = otherObject,它会起作用。我不确定这是你的问题,这就是为什么你应该测试我的建议。或者使用Object.assign或其他东西来更改引用,并查看UI是否更新。 – Epitouille

回答

1

你的数据newObj具有由VUE定义的getter和setter。当调用者被调用时,UI被重新渲染。当您更改参考newObj时,而不是在您更改其值时,触发器会被触发。我的意思是:

this.newObj = {} // triggered 

this.newObj['key'] = 'value' // not triggered 

您可以在属性this.newObj上添加深层观察者。或者改变它的参考:

this.newObj = Object.assign({}, this.newObjec); 

其中创建对象的副本newObject

这里是小提琴更新。

https://jsfiddle.net/749nc5d2/

+0

我做了'var scalfold = this.newObj [key];删除this.newObj [key]'然后'this $ set(this.newObj,key,scalfold)' - 并且它工作。你认为这是一个错误的方法吗? (只是出于好奇而问,你的方法看起来非常清楚和正确的方式,只是测试它,它的作品像魅力) – senty

+0

https://vuejs.org/v2/guide/reactivity.html这是一个非常有趣的链接。默认情况下,只有对象的引用是被动的。无效意味着更新UI(以及值更改时的其他内容)。 'this。$ set'将一个键添加到一个被动的对象。所以当你第一次创建'this.newObj'时,你可以用这个$ set创建它,你的对象将完全被动。下面的链接显示了2个方法(this。$ set和Object.assign) – Epitouille