Vue - 组件道具没有正确观察对象变化

Posted

技术标签:

【中文标题】Vue - 组件道具没有正确观察对象变化【英文标题】:Vue - component props not watching object changes properly 【发布时间】:2018-01-15 00:51:47 【问题描述】:

我的根目录中有两个对象 - objnewObj。我用deep: true 观察我的obj 对象的变化,并在变化时相应地更新newObj。

在我的 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>
  `
)

【问题讨论】:

您可以尝试更新直接this.newObj 而不是this.newObj 中的密钥。最后你可以用this.newObj = JSON.parse(JSON.stringify(this.newObject))作弊。 deep: true 申请 obj 而不是 newObj 所以如果引用没有更新,UI 也不会更新 但是,我如何才能附加到现有的键值?它不会只是覆盖现有值并仅保留此项目吗?我将不胜感激任何指导 您可以附加到现有的键值,但您需要告诉 vuejs 您的对象已更改并且应该重新渲染。 Vuejs 默认只看 newObj 的引用,这意味着如果你像这样改变这个对象:this.newObj = otherObject,它会起作用。我不确定这是你的问题,这就是为什么你应该测试我的建议。或者使用 Object.assign 或其他东西来更改引用并查看 UI 是否更新。 问题是,我不想完全复制obj里面的东西,我想在newObj里面放不同的数据,但是根据obj里面的变化。这就是为什么我不能使用this.newObj = otherObj。还是我误解了您的解决方案?如果您能添加答案或将其放在小提琴中,我将不胜感激.. fiddle 不灵了,扔到控制台:Uncaught ReferenceError: Vue is not defined at window.onload 【参考方案1】:

你的数据newObj 有一个由 vue 定义的 getter 和 setter。调用 setter 时,会重新渲染 UI。当您更改 newObjreference 时触发 setter,而不是在您更改其值时触发。我的意思是:

this.newObj =  // triggered

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

您可以在属性this.newObj 上添加深度观察者。或者用技巧改变它的引用:

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

创建对象newObject的副本。

这里是更新的小提琴。

https://jsfiddle.net/749nc5d2/

【讨论】:

我做了var scalfold = this.newObj[key]; delete this.newObj[key] 然后this.$set(this.newObj, key, scalfold) - 它奏效了.. 你认为这是一个错误的方法吗? (只是出于好奇而询问。您的方法似乎非常清晰和正确。刚刚测试它,它就像魅力一样) vuejs.org/v2/guide/reactivity.html 这是一个非常有趣的链接。默认情况下,只有对象的引用是响应式的。反应式意味着,更新 UI(以及当值改变时的其他东西)。 this.$set 将键添加到将是反应性的对象。因此,当您第一次创建 this.newObj 时,您可以使用 this.$set 创建它,您的对象将是完全反应式的。下面的链接显示了 2 个方法(this.$set 和 Object.assign)

以上是关于Vue - 组件道具没有正确观察对象变化的主要内容,如果未能解决你的问题,请参考以下文章

vue.js中的Watcher不会收到值

Vue Watch没有触发

Vue.js:如何在组件初始化时触发观察器函数

Vue 道具没有在子组件中正确更新

Vue - 如果添加或修改了对象,则深度观察对象数组的变化

观察 Vue 中的异步外部 DOM 变化