computed

computed 是计算属性,它会根据你所依赖的数据动态显示新的计算结果,可以直接使用函数名当做属性引用

  1. var app = new Vue({
  2. el: "#app",
  3. data: {
  4. firstName: "Lebron",
  5. lastName: "James",
  6. },
  7. computed: {
  8. fullName: function () {
  9. return this.firstName + " " + this.lastName
  10. },
  11. },
  12. template: `
  13. <div>
  14. <h2>{{ fullName }}</h2>
  15. </div>`,
  16. });

computed 是一个简写属性(完整有 setget 两个方法)

var vm = new Vue({
  data: { a: 1 },
  computed: {
    // 仅读取
    aDouble: function () {
      return this.a * 2
    },
    // 读取和设置
    aPlus: {
      get: function () {
        return this.a + 1
      },
      set: function (v) {
        this.a = v - 1
      }
    }
  }
})
vm.aPlus        // => 2
vm.aPlus = 3
vm.a            // => 2
vm.aDouble      // => 4

相比于 watch,计算属性拥有数据缓存机制(methods 也没有)

var app = new Vue({
  el: '#app',
  data: { a: 1 },
  methods: {
    getA: function () {
      console.log('methods 调用多少次就会输出多少次');
      return this.a
    }
  },
  computed: {
    aPlus: function () {
      console.log('不管调用多少次 computeds 只会输出一次');
      return this.a + 1
    }
  }
})

在 Vue 的 template 模板内是可以写一些简单的 js 表达式的,但是在模版中放入太多声明式的逻辑会让模板本身过重,尤其当在页面中使用大量复杂的逻辑表达式处理数据时,会对页面的可维护性造成很大的影响,而 computed 的设计初衷也正是用于解决此类问题。

watch

watch 是一个对象,键是 data 中要监听的数据,值是对应的回调函数,或者包含选项的对象。当依赖的 data 的数据变化,执行回调,在回调中会传入 newValoldVal 两个参数。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。

var app = new Vue({
  el: "#app",
  data: {
    firstName: "Foo",
    lastName: "Bar",
    fullName: "Foo Bar",
  },
  watch: {
    firstName: function (newVal, oldVal) {
      console.log("firstName 发生了变化:" + oldVal + "——>" + newVal);
      this.fullName = newVal + " " + this.lastName
    },
    lastName: function (newVal, oldVal) {
      console.log("lastName 发生了变化:" + oldVal + "——>" + newVal);
      this.fullName = this.firstName + " " + newVal
    },
  },
  template: `
    <div>
      <h2>{{ fullName }}</h2>
    </div>`,
});

监听复杂类型可以使用对象的方式,回调函数名必须为 handler

如果不设置 deep 属性,将监听不到 obj.a 的改变,不过 obj 的属性依旧可以监听

var app = new Vue({
  el: "#app",
  data: {
    obj: {
     a: "a" 
    }
  },
  watch: {
    obj: {
      handler: function (newVal, oldVal) {、
        console.log("obj 发生了变化");
        console.log(newVal);
        console.log(oldVal);
        deep: true, // 该属性设定在任何被侦听的对象的 property 改变时都要执行 handler 的回调,不论其被嵌套多深
      },
  },
});

打印的结果,发现 oldValnewVal 值是一样的,因为它们的引用指向同一个对象/数组。Vue 不会保留变更之前值的副本,所以深度监听虽然可以监听到对象的变化,但是无法监听到具体对象里面那个属性的变化

可以直接对用 对象.属性 的方法监听单个属性的变化

var app = new Vue({
  el: "#app",
  data: {
    obj: {
     a: "a" 
    }
  },
  watch: {
    obj: {
      handler: function (newVal, oldVal) {、
        console.log("obj 发生了变化");
        console.log(newVal);
        console.log(oldVal);
        deep: true,
      },
    "obj.a": {
      handler: function (newVal, oldVal) {
        console.log("obj.a 变了");
        console.log(newVal);
        console.log(oldVal);
      },
      immediate: true, // 该属性设定该回调将会在侦听开始之后被立即调用
    },
  },
});

注意:不应该使用箭头函数来定义 watcher 函数,因为箭头函数没有 this,它的 this 会继承它的父级函数,但是它的父级函数是 window,导致箭头函数的 this 指向 window,而不是 Vue 实例

vm.$watch() 的用法和 watch 回调类似

vm.$watch("n", function(newVal, oldVal){
  console.log("n 变了");
},{deep: true, immediate: true})

区别

计算属性:

  • 支持缓存,只有依赖数据发生改变,才会重新进行计算
  • 不支持异步,当 computed 内有异步操作时无效,无法监听数据的变化
  • 默认深度依赖

侦听属性:

  • 不支持缓存,数据变,直接会触发相应的操作
  • watch 支持异步
  • 默认浅度观测

参考文章