【问题标题】:Why is a watched object not updating in vue为什么被监视的对象没有在 vue 中更新
【发布时间】:2017-05-30 10:49:50
【问题描述】:

我知道有很多这样的问题,但这个问题有点不同。我看了reactivity in depth 并认为我对这个主题有一个公平的理解,但我无法理解的一件事是:

tl;dr

为什么当使用currentValue = Object.assign=({}, currentValue, initValue) 初始化而不是直接赋值currentValue = initValue; 时,监视的属性寄存器会发生变化?

我的 vue 组件模型上有一个注册对象,scoreRules

mounted钩子里,

  1. 我使用

    重新初始化模型的 scoreRules

    this.$data.scoreRules = initScoreRules;

    (initScoreRules 作为道具传入,但我将其声明为本地 为了这个问题的目的,下面的变量)。

  2. 观察scoreRules 的变化并在对象发生变化时记录“分数已更改”。

这个 sn-p 显示了这个场景

new Vue({
  el: '#app',
  data() {
    return {
      scoreRules: {
        type: "number",
        minimum: null,
        maximum: null
      }
    }
  },
  mounted() {
  let initScoreRules = {type: "number"};
    this.$data.scoreRules = initScoreRules;
    this.$watch('scoreRules', ()=>{console.log("score has been changed")}, {deep: true});
  }
});
<html>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.js"></script>
</head>

<body>
  <div id="app">
    <span>Minimum score</span>
    <input type="number" name="minimumScore" v-model.number="scoreRules.minimum" />
</body>

</html>

现在,当我在输入中输入内容时,手表不会捕捉到这种变化,并且控制台不会记录任何内容。

如果我现在重新初始化 scoreRules 使用 this.$data.scoreRules = Object.assign({}, this.$data.scoreRules, initScoreRules);

new Vue({
  el: '#app2',
  data() {
    return {
      scoreRules: {
        minimum: null
      }
    }
  },
  mounted() {
    let initScoreRules = {};
    this.$data.scoreRules = Object.assign({}, this.$data.scoreRules,  initScoreRules);
    this.$watch('scoreRules', () => {
      console.log("score has been changed")
    }, {
      deep: true
    });
  }
});
<html>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.js"></script>
</head>

<body>
  <div id="app2">
    <span>Minimum score</span>
    <input type="number" v-model.number="scoreRules.minimum" />
  </div>
</body>

</html>

注册更改并将输出记录到控制台。为什么?我怀疑它与 JS 本身的内部有关,但我不确定具体如何。

【问题讨论】:

  • 对象是引用类型。这就是为什么您需要使用Object.assign 克隆一个对象,而不是仅仅使用= 指向一个现有对象。当您创建一个新对象时,Vue 有机会为该对象及其属性设置其反应环境。
  • 我明白了。使用= 进行直接分配将指向一个非反应性对象,因此不会注册对它的更改。现在看来很明显。谢谢。

标签: javascript vue.js


【解决方案1】:

初始对象包含属性minimummaximum。然后,在mounted 中,你这样做:

let initScoreRules = {type: "number"};
this.$data.scoreRules = initScoreRules;

这意味着现在scoreRules 对象没有这些属性。

Vue 只能观察以下属性的变化:

  • data() 中预定义(您在mounted 中做了但后来又取消了)
  • 设置为Vue.set() / this.$set()
  • 存在于分配给反应属性的对象上。

最后一点也是为什么第二个例子有效的解释:在这里,基本上你是这样做的(省略 Object.assign 冗长,因为它会分散注意力):

this.$data.scoreRules = { minimum: null }; 

此属性将是反应性的。

在这里阅读更多:

https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats

【讨论】:

  • 谢谢@Linus。总结得很到位。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-16
  • 2019-10-17
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
相关资源
最近更新 更多