computed 和 watch

75 阅读2分钟

computed

  • computed 是 计算属性,它会根据所依赖的数据计算新的结果。
  • 具备 缓存 功能,会缓存所依赖的属性的值。当缓存所依赖的属性的值发生变化才会重新计算。
  • computed 的设计初衷是用于解决 template 模板({{}})中声明式逻辑过多造成不便的问题。 Vue的模板内可以写表达式,但在模板中放入太多的逻辑会让模板过重且难以维护。对于任何复杂逻辑,Vue 推荐使用计算属性。

示例一:CodeSandbox

示例二:

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

  • watch 指 侦听 / 监听,当响应式属性发生变化时会触发一个回调函数,Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个 property。有两个参数(oldVal 和 newVal)
  • 注意: 不能使用箭头函数来定义 watcher 函数。
    • ( 理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例)

示例:CodeSandbox

new Vue({
  data: {
    n: 0,
    obj: {
      a: "a",
    },
  },
  template: `
      <div>
        <button @click="n +=1">n + 1</button>
        <button @click="obj.a+='hi'">obj.a + 'hi'</button>
        <button @click="obj={a:'a'}">obj = 新对象</button>
      </div>
     
  `,
  watch: {
    n: {
      handler() {
        console.log("n变了");
      },
      immediate: true,
      //immediate:第一次执行函数时是否立刻渲染
    },
    obj: {
      handler() {
        console.log("obj变了");
      },
      deep: true,
      //deep可理解为向深层看,true时就是当obj里面的内容变化时,也认为obj变了
      //默认是deep: false。也就是自身地址变化才算变。默认可不写,如下:
      /* 
      obj() {
        console.log("obj变了");
      },
      */
    },
    "obj.a": function () {
      console.log("obj.a变了");
    },
  },
}).$mount("#app");

watch 的写法

除了上述例子中的写法外,还可以用 vm.$watch()方法写,比如

new Vue({
  watch: {
    n() {
        console.log("n变了");
    }
  },
})

可以写成

const vm = new Vue({ });
vm.$watch('n',function(){
  console.log("n变了");
})

还可以使用生命周期钩子

new Vue({
  created() {
    this.$watch(
      "n",
      function () {
        console.log("n变了");
      }
    )
  }
})

deep 选项

  • 作用是发现对象内部值的变化。

示例:给data添加obj,里面是 a: "a"。添加两个按钮,用watch监听。

new Vue({
  data: {
    obj: {
      a: "a",
    },
  },
  template: `
      <div>
        <button @click="obj.a+='hi'">obj.a + 'hi'</button>
        <button @click="obj={a:'a'}">obj = 新对象</button>
      </div>
     
  `,
  watch: {
    obj() {
        console.log("obj变了");
      },
    },
    "obj.a": function () {
      console.log("obj.a变了");
    },
  },
}).$mount("#app");

当我们点击按钮【obj.a + 'hi'】时发现打印了obj.a变了,但是不打印obj变了,按理来说应该都打印。这里看出 Vue 没有发现obj内部值的变化。

原因:Vue 有一个 deep 选项。用来发现对象内部值的变化。但是默认 deep : false.也就是如果对象是嵌套的,不会去监听其内部。可以改成 deep : true,就可以对对象内部进行监听。 如下:

 watch: {
    obj:{
      handler(){
        console.log("obj变了");
      },
        deep: true
      },
    },
    "obj.a": function () {
      console.log("obj.a变了");
    },
  },

immediate

  • 在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调。也就是回调将会在侦听开始之后被立即调用。

示例:代码执行便会立即打印出n变了

new Vue({
  data: {
    n: 0,
  },
  template: `
      <div>
        <button @click="n +=1">n + 1</button>
      </div> 
  `,
  watch: {
    n: {
      handler() {
        console.log("n变了");
      },
      immediate: true,
      //immediate:第一次执行函数时是否立刻渲染
    },
}).$mount("#app");

区别

  1. computed是计算属性,具有缓存功能;watch 是指侦听,没有缓存的功能,每次都需要执行函数。
  2. 需要产生新数据或简化 template 选择 computed ;需要监听数据变化或想在数据变化时做些操作选择 watch。
  3. computed 不支持异步操作, watch 支持异步操作。