计算属性和监听属性应用详解

1,936 阅读5分钟

计算属性和监听属性

两者表面看起来都可以根据监听的值做出相应的行为的属性,那么究竟有什么优缺点,各自的最佳应用场景分别是什么呢

计算属性

  • 计算属性的原理是通过监听依赖值得变化,从而动态返回内容,监听是一个过程,在监听到值变化时候,触发一个回调
  • 数据可以进行逻辑处理,减少模板中计算逻辑(设计的主要目的)
  • 对计算属性中的数据进行监视
  • 依赖固定的数据类型(响应式数据)

计算属性的组成

  • 通过get和set分别来获取计算属性和设置计算属性,默认只有get,需要set需要自己添加,也就是我们常写的计算属性中的那个回调函数,就是他的set,而且不是直接修改计算属性,而是修改他的依赖

例子1:

computed: {
  fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      //this.fullName = newValue 这种写法会报错
      var names = newValue.split(' ')
      this.firstName = names[0]//对它的依赖进行赋值
      this.lastName = names[names.length - 1]
    }
  }
}

小结:现在再运行fullName = 'i am other',setter被调用,然后firstName和lastName被更新,计算属性必须是一个函数,而且要有返回值

计算属性和方法的区别

  • 两者最主要的区别:computed 是可以缓存的,methods 不能缓存;**只要相关依赖没有改变,多次访问计算属性得到的值是之前缓存的计算结果,不会多次执行。**网上有种说法就是方法可以传参,而计算属性不能,其实并不准确,计算属性可以通过闭包来实现传参
:data="closure(a, b, c)"
computed: {
 closure () {
   return function (a, b, c) {
        /** do something */
        return data
    }
 }
}

监听属性

  • Vue提供了一种更通用得方式来观察和响应Vue实例上的数据变动:监听属性Watch,其中可以执行任何逻辑,例如:函数节流,ajax异步获取数据

例子1:我们先看一个demo

<template>
  <div>
    <el-input v-model="demo"></el-input>
    {{value}}
  </div>
</template>
<script>
  export default {
    name: 'index',
    data() {
      return {
        demo: '',
        value: ''
      };
    },
    watch: {
      demo(val) {
        this.value = this.demo;
      }
    }
  };
</script>

小结:watch来直接监听demo,如果demo的值变化,value的值也会一起变化

例子2:watch监听对象

<template>
  <div>
    <el-input v-model="demo.name"></el-input>
    {{value}}
  </div>
</template>
<script>
  export default {
    name: 'index',
    data() {
      return {
        demo: {
          name: ''
        },
        value: ''
      };
    },
    computed: {
      newName() {
        return this.demo.name;
      }
    },
    watch: {
      newName(val) {
        this.value = val;
      }
    }
  };
</script>

小结:watch直接监听一个对象是不行的,所以先通过计算属性监听,然后watch监听计算属性

例子3:深度监听,deep

<div id="app">
  <input type="text" v-model="childrens.name" />
  <input type="text" v-model="lastName" />
</div>


<script type="text/javascript">
var vm = new Vue( {
el: '#app',
data: {
childrens: {
name: '小强',
age: 20,
sex: '男'
},
tdArray:["1","2"],
lastName:"张三"
},
watch:{
childrens:{
handler:function(val,oldval){
console.log(val.name)
},
deep:true//对象内部的属性监听,也叫深度监听
},
'childrens.name':function(val,oldval){
console.log(val+"aaa")
},//键路径必须加上引号
lastName:function(val,oldval){
console.log(this.lastName)
}
},//以V-model绑定数据时使用的数据变化监测
} );
vm.watch("lastName",function(val,oldval){
    console.log(val)
  })//主动调用watch方法来进行数据监测
</script>

<script type="text/javascript"> var vm = new Vue( { el: '#app', data: { childrens: { name: '小强', age: 20, sex: '男' }, tdArray:["1","2"], lastName:"张三" }, watch:{ childrens:{ handler:function(val,oldval){ console.log(val.name) }, deep:true//对象内部的属性监听,也叫深度监听 }, 'childrens.name':function(val,oldval){ console.log(val+"aaa") },//键路径必须加上引号 lastName:function(val,oldval){ console.log(this.lastName) } },//以V-model绑定数据时使用的数据变化监测 } ); vm.watch("lastName",function(val,oldval)console.log(val))//主动调用watch("lastName",function(val,oldval){ console.log(val) })//主动调用watch方法来进行数据监测 </script>

小结:对象内部的属性监听需要深度监听,键路径必须加引号,数组的变化不需要深度watch

例子4:这个例子大家可以跑一下,涵盖了大部分情况

<template>
  <div class="attr">
    <h1>watch属性</h1>
    <h2>{{ $data }}</h2>
    <button @click="() => (a += 1)">修改a的值</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      a: 1,
      b: { c: 2, d: 3 },
      e: {
        f: {
          g: 4
        }
      },
      h: []
    };
  },
  watch: {
    a: function(val, oldVal) {
      this.b.c += 1;
    },
    "b.c": function(val, oldVal) {
      this.b.d += 1;
    },
    "b.d": function(val, oldVal) {
      this.e.f.g += 1;
    },
    e: {
      handler: function(val, oldVal) {
        this.h.push("浪里行舟");
      },
      deep: true //用于监听e对象内部值的变化
    }
  }
};
</script>

小结:当点击按钮,a的值加一,然后触发a的监听,b.c加一,然后触发b.c以此触发下去,这里可以注意到,使用对象里的属性时候键路径必须加引号。

区别

  • watch:监测的是属性值, 只要属性值发生变化,其都会触发执行回调函数来执行一系列操作。

  • computed:监测的是依赖值,依赖值不变的情况下其会直接读取缓存进行复用,变化的情况下才会重新计算。

  • 计算属性不能执行异步任务,计算属性必须同步执行。也就是说计算属性不能向服务器请求或者执行异步任务。如果遇到异步任务,就交给侦听属性。watch也可以检测computed属性。

总结

计算属性适合用在模板渲染中,某个值是依赖了其它的响应式对象甚至是计算属性计算而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。

  • computed能做的,watch都能做,反之则不行
  • 能用computed的尽量用computed