vue:watch和computed

151 阅读5分钟

computed计算属性

  1. 被计算出来的属性就是计算属性,类似过滤器,对绑定到view的数据进行处理
  2. 计算属性就是当依赖的属性的值发生变化的时候,才会触发他的更改,如果依赖的值,不发生变化的时候,使用的是缓存中的属性值。

computed的getter和setter

  1. computed的属性可以被视为是data一样,可以读取和设值。因此,在computed中可以分为getter(读取)和setter(设值).
  2. 一般情况下,是没有setter的,computed只是预设了getter,也就是只能读取,不可以改变设值。所以,computed默认格式(是不表明getter函数的).
  3. 当赋值给计算属性的时候,将调用setter函数。多用于在模板组件中需要修改计算属性自身的值的时候。

get

<div id="example">
  <p>firstName: "{{ firstName }}"</p>
  <p>lastName: "{{ lastName }}"</p>
   <p>fullName: "{{ fullName }}"</p>
</div>
export default {
  name: "App",
  data(){
    return {
      firstName:'张',
      lastName:'小明'
    }
  },
  computed:{
      fullName: function(){
        return this.firstName + ' ' + this.lastName
      }
  }

};

注意:fullName不可在data里面定义, 如果定义会报错,因为对应的computed作为计算属性定义fullName并返回对应的结果给这个变量,变量不可被重复定义和赋值

get+setter

正常只有getter,当给计算属性赋值的时候,就用到了setter。多用于在模板组件中需要修改计算属性自身的值的时候。

<template>
  <div id="example">
    <p>firstName: "{{ firstName }}"</p>
    <p>lastName: "{{ lastName }}"</p>
    <p>fullName: "{{ fullName }}"</p>
     <p>fullName-setter: "{{ setter }}"</p>
     <button @click="change">change setter</button>
</div>
</template>

<script>


export default {
  name: "App",
  data(){
    return {
      firstName:'张',
      lastName:'小明',
      setter:''
    }
  },
  computed:{
      fullName: {
        get(){ //回调函数 当需要读取当前属性值时执行,根据相关数据计算并返回当前属性的值
          return this.firstName + ' ' + this.lastName
        },
        set(val){//监视当前属性值的变化,当属性值发生变化时执行,更新相关的属性数据
          console.log(val)//val就是fullName的最新属性值
          this.firstName = '使用了setter'

        }
        
      }
  },
  methods:{
    change(){
      this.fullName = '使用了setter' //触发了fullName的set
      
    }
  }

};
</script>

只有当计算属性中的属性被直接赋值的时候,才会走setter函数,而且,setter函数和getter函数是相互独立的,不是说,走setter函数,就必须走getter函数。

computed注意事项

  1. 缓存:
  • 如果依赖的属性没有发生变化,就不会重新计算,而是立即返回之前的计算结果。
  • 当模板中不使用fullName,即使firstName发生改变之后,也不会走computed。不是说我们更改了getter中使用的变量(即依赖的属性),就会触发computed的更新,他有一个前提是computed里的值必须要在模板中使用才可以。、

watch 监听/侦听

watch监听一个值的变化。 当firstName发生变化时,监听并且执行。

<div>
      <p>FullName: {{fullName}}</p>
      <p>FirstName: <input type="text" v-model="firstName"></p>
</div>
 
new Vue({
  el: '#root',
  data: {
    firstName: 'Dawei',
    lastName: 'Lou',
    fullName: ''
  },
  watch: {
    firstName(newName, oldName) {
      this.fullName = newName + ' ' + this.lastName;
    }
  } 
})

immediate

上面的例子是值变化时候,watch才执行,我们想让值最初时候watch就执行就用到了handler和immediate属性

watch: {
  firstName: {
    handler(newName, oldName) {
      this.fullName = newName + ' ' + this.lastName;
    },
    // 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法,如果设置了false,那么效果和上边例子一样
    immediate: true
  }
}

deep

当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听。

new Vue({
  el: '#root',
  data: {
    cityName: {id: 1, name: 'shanghai'}
  },
  watch: {
    cityName: {
      handler(newName, oldName) {
      // ...
    },
    deep: true, //设置deep: true 则可以监听到cityName.name的变化
    immediate: true
    }
  } 
})

此时会给cityName的所有属性都加上这个监听器,当对象属性较多时,每个属性值的变化都会执行handler。
如果只需要监听对象中的一个属性值,则可以做以下优化:使用字符串的形式监听对象属性:

watch: {
    'cityName.name': {
      handler(newName, oldName) {
      // ...
      },
      deep: true,
      immediate: true
    }
  }

watch总结

  1. 不支持缓存,数据变,直接会触发相应的操作;
  2. watch支持异步;
  3. 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
  4. 当一个属性发生变化时,需要执行对应的操作;一对多;
  5. 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,   * immediate:组件加载立即触发回调函数执行,   * deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。

watch和computed

  1. 从属性名上,computed是计算属性,也就是依赖其它的属性计算所得出最后的值
  2. watch是去监听一个值的变化,然后执行相对应的函数。
  3. 从实现上,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时才会重新调用对应的getter来计算。
  4. watch在每次监听的值变化时,都会执行回调。其实从这一点来看,都是在依赖的值变化之后,去执行回调。
  5. 很多功能本来就很多属性都可以用,只不过有更适合的。如果一个值依赖多个属性(多对一),用computed肯定是更加方便的。如果一个值变化后会引起一系列操作,或者一个值变化会引起一系列值的变化(一对多),用watch更加方便一些。
  6. watch的回调里面会传入监听属性的新旧值,通过这两个值可以做一些特定的操作。immediate表示是否第一次渲染就执行这个函数。deep:是否坚挺这个对象里面的属性的变化。computed通常就是简单的计算。
  7. atch和computed并没有哪个更底层,watch内部调用的是vm.$watch,它们的共同之处就是每个定义的属性都单独建立了一个Watcher对象。