computed 、watch

2020年的最后一篇博客了,记录一下Vue中computed和watch的用法和区别

computed

前言:Vue模版(template)中的表达式{{}}可以直接放入简单的运算,如 {{ msg.split('').reverse().join('') }},但如果模版中过多的出现这样的运算语句会使模版变得逻辑复杂且冗余,会对页面的可维护性造成很大的影响。

于是Vue变推出了计算属性computed来解决此类问题,把复杂语句放入computed中,使模板中的运算逻辑更简单。

<div id="example">
  <p>Original message: "{{ message }}"</p>
  <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>

var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    },
    messagePlus: {
       get: function () {
            return this.message + "hello"
          },
       set: function (v) {
            this.message = v + "olleh"
          }
       }
    }
})
    vm.messagePlus="hello"

computed计算属性中

  • 声明函数来读取结果值,只有只读属性,默认实现的就是getter,在模版上可以直接使用函数名来获取结果,不需要加上()
  • 如果使用箭头函数,则this不会指向实例vm,而是会指向全局window,或gobal
  • 如果既要读取结果又要对结果进行设置,则要在computed中声明为属性,并设置getter和setter方法

缓存

计算属性是基于它们的依赖的响应式数据进行缓存的。只在相关响应式数据发生改变时它们才会重新调用对应的getter来计算。

上例中,只要 message 还没有发生改变,再次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

computed 应用场景

  1. 适用于一些重复使用数据或复杂及费时的运算。我们可以把它放入computed中进行计算, 然后会在computed中缓存起来, 下次就可以直接获取了。

  2. 如果我们需要的数据依赖于其他的数据的话, 我们可以把该数据设计为computed中。

ps:如果不想被缓存,则使用方法methods,methods方法中是每次调用, 都会执行函数

watch

watch它是一个对data的数据监听回调, 当依赖的data的数据变化时, 会执行回调handler函数。在回调中会传入newVal和oldVal两个参数。Vue实列将会在实例化时调用$watch(), 他会遍历watch对象的每一个属性。

用法

watch: {
    obj1: function (val, oldVal) {
     ...
    },
    // 方法名
    obj2: 'someMethod',
    // 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
    obj3: {
      handler: function (val, oldVal) { /* ... */ },
      deep: true
    },
    // 该回调将会在侦听开始之后被立即调用,第一次渲染就触发这个函数
    obj4: {
      handler: 'someMethod',
      immediate: true
    },
    // 可以传入回调数组,它们会被逐一调用
    obj5: [
      'handle1',
      function handle2 (val, oldVal) { /* ... */ },
      {
        handler: function handle3 (val, oldVal) { /* ... */ },
        /* ... */
      }
    ],
    // 对obj1对象中的属性a监听
     'obj1.a': function (val, oldVal) { /* ... */ }
  }

选项

  • immediate

​ immediate是设置第一次渲染是否要触发这个函数,默认是false(由无到有不触发,变化才触发)。

  • deep

    watch监听数据是否发生变化的规则是:简单类型直接比较值有没有变化,复杂类型对象要看地址有没有变化

    所以当obj中的a变化了watch不会认为obj改变了,因为地址没有变,obj赋值给新地址watch才会认为改变了,如果你需要a变了,obj也要变,就可以设置deep属性为true。

    deep的作用就是否深度监听某个对象的值, 该值默认为false,注意监听数组的变更不需要这么做。

注意

  1. 不应该使用箭头函数来定义 watcher 函数,因为箭头函数本身没有this,它会继承外部的this,watcher函数外部的this不会是实例vm而是全局作用域的window或者是gobal 就无法获取到实例vm内部的数据,所以要使用普通function xxx或其简写来声明watcher函数,这样当Vue调用函数时必定会传入vm来作为其this

总结

  • computed是计算属性,watch是监听数据的变化,再触发回调函数

  • computed是对属性的值进行计算, 在Vue的 template模板内({{}})使用时可以不用加括号,直接使用。它会根据依赖进行缓存 如果依赖的值不变,它就不会重新计算。

  • watch 更像是一个 data 的数据监听回调,当依赖的 data 的数据变化,执行回调,在方法中会传入 newVal 和 oldVal。watch有两个选项immediate和deep,immediate是设置第一次渲染是否要触发这个函数,默认是false,deep 设置是否监听对象内部值的变化,默认是false。

  • computed着重于依赖缓存,计算后得出结果,而watch是执行一个函数,记录变化