【问题标题】:VueJs, difference between computed property and watcher?VueJs,计算属性和观察者之间的区别?
【发布时间】:2017-09-02 19:31:43
【问题描述】:

在 Vue.js 文档中有一个如下示例:

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})

上面的代码是命令式和重复的。将其与计算属性版本进行比较:

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

观察者比计算属性更适合的情况是什么?我应该如何决定选择哪个?文档一直说它更“通用”,但并没有真正说明它的用途。

【问题讨论】:

    标签: vue.js vuejs2


    【解决方案1】:

    计算属性

    计算属性示例:

    computed: {
       val () {
         return this.someDataProperty * someOtherVariable
       }
    }
    

    这段特定的代码有什么作用?

    1. 它为组件创建一个名为val的属性(在原型上,<vueInstanece>.hasOwnProperty('val') 将显示false

    2. 它有一个依赖树,在这种情况下由 reactive 属性(数据属性,其他计算属性)组成:this.someDataProperty,这意味着依赖关系发生变化的那一刻,计算属性将重新计算。

    3. 虽然有争议,但不能将参数传递给它。所以像

      computed: {
        val (flag) {
          return (flag === 1) 
            ? this.someDataProperty * someOtherVariable 
            : this.someDataProperty * 5
          }
      }
      

      做不到

    [编辑]参见:https://vuejs.org/v2/guide/computed.html#Computed-Setter

    观察者

    观察者样本:

    watch: {
       val (n, o) {
         console.log(n, o)
       }
    }
    
    1. 它不会创建任何新属性,但会监视反应性属性的变化。

    2. 只观察一个特定的属性,与计算不同,任何依赖属性的变化都会导致重新计算。

    3. 具有新旧值的参数。


    所以计算属性将是要走的路,如果:

    您想要一个始终依赖于其他属性的属性。就像模板的文本格式一样,甚至是您代码中的示例。

    或者减少可变长度,因为这很常见:

    this.$store.state.someProperty.someNestedProperty.someDeeplyNestedProperty
    

    可以简化为:

    computed: {
      someDeeplyNestedProperty () {
         return this.$store.state.someProperty.someNestedProperty.someDeeplyNestedProperty
      }
    }
    

    不只是减少可变大小,每次商店更新时,someDeeplyNestedProperty 中都会有最新的值。


    如果您想查看某个反应性属性是否已更改为有利值以了解您已准备好执行某项操作,那么 Watchers 非常有用。

    喜欢:

    watch: {
      somethingSelected() {
        this.router.push('someOtherRoute')
      }
    }
    

    编辑:我看到了Flavio Copes 的一些好文章,其中列出了每个用例(方法、计算道具、观察者)的常见用例:

    什么时候使用方法

    • 对 DOM 中发生的某些事件做出反应

    • 在组件中发生某些事情时调用函数。您可以从计算属性或观察者调用方法。

    何时使用计算属性

    • 您需要从现有数据源组合新数据
    • 您在模板中使用了一个由一个或多个数据属性构建的变量
    • 您希望将复杂的嵌套属性名称简化为更易读、更易于使用的名称,并在原始属性更改时对其进行更新
    • 您需要从模板中引用一个值。在这种情况下,最好创建一个计算属性,因为它是缓存的。
    • 您需要监听多个数据属性的变化

    何时使用观察者

    • 您想在数据属性更改时进行监听并执行一些操作
    • 你想监听一个 prop 值的变化
    • 您只需要收听一个特定的属性(您不能同时观看多个属性)
    • 您希望观察数据属性,直到它达到某个特定值,然后执行某些操作

    【讨论】:

    • 只关注一个特定属性是什么意思?你的意思是在OP给出的例子中,只有this.fullName可以同时用于watch -> firstNamewatch -> lastName
    • 在 OP Watch 的示例中,将观察到属性 this.firstnamethis.lastname。如果。它们中的任何一个都将更改,this.fullname 将根据表达式 this.fullname = this.firstname +this.lastname 重新评估 请注意,这些值之一将是 val,即手表提供的新值。
    • 好的,但是我很困惑为什么你写 Watches only one specific property 现在你解释说 OP 的例子是看 2 个属性 ...
    • 在 OP 的情况下,watch 设置在两个数据属性上,两者都是字符串,所以不清楚我的意思。需要明确的是,您可以查看 N 个数据属性,但如果其中一个是对象示例:person: { name: "Jack", age: 30, friends: [{name: "Sally", age:21}] } 那么对人的监视将不会查看对象整个深度内的变化,您可以查看 person.name 或 @987654344 @ 或person.friends
    • 我可以说对于computed,如果没有在模板或其他computed中使用,那么就不会被计算?
    【解决方案2】:

    计算属性有一个非常特定的目的:组合从其他数据派生的新数据。每当您有一些数据并且需要在模板中使用它之前对其进行转换、过滤或以其他方式对其进行操作时,就会使用它们。

    计算属性总是必须返回一个值,不应该有任何副作用,而且它们必须是同步的。

    因此,在很多情况下计算属性对您没有帮助,例如:您的组件接收到一个 prop,并且每当 prop 发生更改时,您的组件都必须发出 ajax 请求。为此,您需要一个观察者。

    观察者不如计算属性有用,因此您应该始终考虑计算属性是否可以解决您的问题,如果不能解决问题,请仅使用观察者(或有时是方法)。

    【讨论】:

      【解决方案3】:

      当您想要改变一个值或根据其他一些值更改执行操作时,您可以使用观察器。一个很好的例子是当你基于一个 prop 设置一个值并且你想对任何变化做出反应时:

      Vue.component('my-comp',{
        template: '#my-comp',
        props: ['username'],
        created() {
          this.user = this.username;
        },
        watch:{
          username(val){
            this.user = val;
          }
        },
        data(){
          return{
            user: ''
          }
        }
      });
      

      查看这个 JSFiddle:https://jsfiddle.net/fjdjq7a8/

      这个例子有点做作,在现实世界中并没有真正起作用,因为我们没有同步值,所以这是一个真实的例子,我在我的 open source projects 之一中使用它:

      Computeds 用于任意操作数据本身,例如连接字符串和计算值。

      【讨论】:

      • 我认为您也可以在手表中使用“立即”并删除创建的方法。
      【解决方案4】:

      就本示例而言,计算属性确实更好。在使用观察者的示例中,请注意这行代码:

      this.fullName = this.firstName + ' ' + val

      与此非常相似:

      this.fullName = val + ' ' + this.lastName

      两者的目的相同,它们都在观察名字或姓氏的变化,并相应地更新fullName。但是由于这永远不会改变并且fullName 将始终由firstNamelastName 组成,因此我们可以避免大惊小怪并创建一个计算属性。那么每次firstNamelastName变化时,fullName都会自动更新。

      在某些情况下,使用观察者会更好。当您想进行一些认真的计算以编写一些异步代码时,观察者可能更合适。

      例如,如果您有以下情况:

      let app = new Vue({
          el: '#app',
          data: {
              name: ""
          }
      });
      

      而您希望,每次 name 发生变化时,都使用它进行 API 调用,获取结果并处理它,那么观察者更合适:

      watchers: {
          "name": function(newValue, oldValue){
               if(newValue != oldValue)} {
                  fetch(url, {method: 'post', body: JSON.stringify({name: this.name})}).then(...);
              }
          }
      }
      

      要使用计算属性执行此操作,您必须实现 computed get()computed set() 属性,这将导致更多代码。

      还请注意,在文档的示例中,我们有一个属性 fullName,它由其他两个属性组合也称为 computed。在我的示例中,name 没有计算出来,从字面意义上来说。我们只是想观察它,所以使用计算属性更像是一种 hack 而不是设计模式。

      【讨论】:

        【解决方案5】:

        观看

        当您想要执行异步或昂贵的操作以响应变化的数据时,请使用 watch。

        计算

        在其他情况下使用计算。计算的属性根据它们的依赖关系进行缓存。主要用于当您只想重新评估其某些依赖项已更改时。

        【讨论】:

          猜你喜欢
          • 2019-10-24
          • 1970-01-01
          • 2016-04-22
          • 1970-01-01
          • 2020-11-20
          • 2016-09-29
          • 2017-04-25
          • 2015-04-28
          • 2021-03-07
          相关资源
          最近更新 更多