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

我的根目录中有两个对象 - obj 和 newObj。我用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

标签: javascript vue.js vuejs2


【解决方案1】:

你的数据newObj 有一个由 vue 定义的 getter 和 setter。调用 setter 时,会重新渲染 UI。当您更改 newObj 的 reference 时触发 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)
猜你喜欢
  • 2021-01-12
  • 2020-03-26
  • 2022-01-02
  • 2017-04-29
  • 2019-06-19
  • 1970-01-01
  • 2020-12-11
  • 2021-08-30
  • 2017-09-07
相关资源
最近更新 更多