如何在 Vue 中正确观察对象?

Posted

技术标签:

【中文标题】如何在 Vue 中正确观察对象?【英文标题】:How to properly watch an object in Vue? 【发布时间】:2022-01-02 05:58:35 【问题描述】:

我正在尝试在计算对象上使用 Vue 观察程序,但它根本不起作用。如果它只是一个字符串,它可以正常工作,但如果它是一个对象,它就不能正常工作。我遵循了 Vue 文档,但是当对象更改时,我仍然没有将任何内容记录到控制台。正如我在 Vue 工具中确认的那样,对象和计算属性的属性正在发生变化。我究竟做错了什么?谢谢

<v-btn small dark @click="test1.asdf = 'blah'">Test</v-btn>
    data() 
      return 
        test1: ,
      
    ,
    computed: 
      test() 
        return this.test1
      
    ,

    watch: 
      test: 
        handler: function(val, oldVal) 
          console.log(oldVal, val);
        ,
        deep: true
      
    

【问题讨论】:

【参考方案1】:

试试这个代码,它工作正常

<template>
  <div id="app">
     test1 
    <hr />
    <button @click="test1.asdf = 'blah'">Click</button>
  </div>
</template>

<script >
export default 
  data() 
    return 
      test1:  asdf: "HEY" ,
    ;
  ,
  computed: 
    test() 
      return this.test1;
    ,
  ,

  watch: 
    test: 
      handler: function (val, oldVal) 
        console.log(oldVal, val);
      ,
      deep: true,
    ,
  ,
;
</script>

我猜在您的情况下,您应该在点击事件的末尾添加.native,例如@click.native="test1.asdf = 'blah'"

【讨论】:

您通过将asdf 属性添加到数据中的test1 对象来修复它 @LawrenceCherone 我喜欢你刚刚编辑的答案听起来不那么粗鲁。小细节意味着很多。干杯 是的,添加 "test1: asdf: "HEY" " 似乎可以解决问题;但是,无论那里的初始数据如何,计算属性都可以正常工作。向对象添加键时,观察者似乎根本不起作用? @BadCoder 这似乎是一个比这更复杂的行为。我刚刚尝试使用test1 = random() 来查看是否会在第二次单击后触发观察者(因此在创建属性asdf 之后),但它也不起作用。当我们尝试创建一个尚不存在的属性时,Vue 不喜欢它。但是,如果您更新整个对象而不是其属性,它会非常有效。 @Ryo 更新整个对象是什么意思?【参考方案2】:

刚刚尝试替换整个对象。它工作得很好,并且无需使用数据中的asdf 属性来初始化您的对象:

<v-btn small dark @click="test1 =  ...test1, asdf: 'blah'">Test</v-btn>

扩展语法...test1 有助于将其他属性保留在目标对象中(如果有),因此您可以安全地添加asdf 属性而不必担心丢失任何内容。

JSFiddle:https://jsfiddle.net/vh72a3bs/22/

【讨论】:

有趣。谢谢(你的)信息。 Vue 是这样工作的很奇怪。 @BadCoder 我同意。就我个人而言,在我使用 JS 框架或库的项目中,我总是更改整个对象,因此我确信任何更新内容(如观察者)都会被正确触发。当然,这是在对象本身不是非常大的情况下(仍然存在性能问题)。很高兴我的回答对您有所帮助,如果您不介意,请不要忘记将其标记为最佳答案!【参考方案3】:

@BadCoder 对象和数组在 javascript 中通过引用传递,而不是通过值传递。这意味着当您像在问题中那样向对象添加键时,您只是添加到同一个对象。它的内容已更改,但您的变量 test1 仍在引用原始对象并且不知道其内容已更新。观察者没有选择这个变化。您可以按照另一位回答者的建议将deep: true 添加到您的观察者中,但这只会观察几个层次的深度,因此如果您有一个包含大量嵌套数据的大型对象,则不理想。在处理数组或对象时触发观察者的最可靠方法是创建该对象的新实例。您可以通过对象破坏来实现这一点。 类似的,

<v-btn small dark @click="test1 =  ...test1, asdf: 'blah'">Test</v-btn>

之所以有效,是因为您正在创建一个新对象(使用以前的对象属性,加上任何新的),触发了观察者。

【讨论】:

以上是关于如何在 Vue 中正确观察对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 vue.js 2 上循环对象观察者?

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

如何观察 javascript 数组中对象的变化?

如何在 vue.js 组件属性中禁用数据观察

托管对象发生故障时如何正确处理 KVO 通知?

Laravel Vue SPA:如何从 Laravel 正确检索 json 对象并将其打印出来?