Vue computed 和 watch 区别

92 阅读2分钟

1. computed 计算属性

不需要加(),根据依赖会自动缓存,如果依赖不变,不会重新计算

<li v-for="(name, index) in nameList" :key="index">{{ name }}</li>
...
data(){
    return {
        username: [
        { familyName: "张", personalName: "三" },
        { familyName: "李", personalName: "四" },
      ],
    }
},
computed: {
    nameList() {
      return this.username.map((val, index) => {
        return val.familyName + val.personalName;
      });
    },
  },

了解:computed 缓存的实现

2. watch 监听数据

当数据发生变化,执行对应的回调

选项:deep

为了发现对象内部值的变化,可以在选项参数中指定 deep: true。注意监听数组的变更不需要这么做。

选项:immediate

在选项参数中指定 immediate: true 将立即以表达式的当前值触发回调:

<span>{{ obj.a }}</span>
<button @click="obj.a = '22222'">改变</button>
...
data(){
    return {
        obj: {
            a: "1111",
        },
    }
}
watch: {
    obj: { // 监听的属性
      handler() {
        console.log("obj变化了");
      },
      deep: true, // 表示对该属性是否进行深度监测
    },
  },

上面例子中obj:{a:'1111'},对于对象是地址引用,只是更改某个属性是不会更改对象的地址,所以对于该对象来说,是没有变化的。如果没有设置deep:true,是不会监听到obj改变

watch是用于监听数据的变化,当某些场景下不想要数据被监听到发生了变化,可以设置标识,如下面例子中的 watchFlag: true

<template>
    <div>
        <span>{{ num }}</span>
        <div>
          <button @click="count(1)">+1</button>
          <button @click="count(-1)">-1</button>
          <button @click="count(2)">+2</button>
          <button @click="count(-2)">-2</button>
        </div>
        <button @click="cancel">撤销</button>
        <div>{{ changeRecord }}</div>
    </div>
 </template>
...
data(){
    return {
        num: 0,
        changeRecord: [],
        watchFlag: true,// 设置标记,true时监听
    }
},
watch: {
    num: {
      handler(newVal, oldVal) {
        if (this.watchFlag) {
          this.changeRecord.push({ from: oldVal, to: newVal });
        }
      },
    },
},
methods:{
    count(i) {
      this.num += i;
    },
    cancel() {
      if (this.changeRecord.length === 0) return;
      let lastRecord = this.changeRecord.pop();
      this.watchFlag = false;//由于撤销导致num变化,此时不想被watch,所以设置为false
      this.num = lastRecord.from;
      this.$nextTick(() => {//由于watch是异步的,底层是根据nextTick实现,所以当watch完成后,就可以立马执行这个nextTick,将标记设置为true
        this.watchFlag = true;
      });
    },
}

watch.gif

上述例子需要注意:

  • watch 异步,是通过nextTick实现的
  • 当在某些情况下不需要监听时,可以设置一个标记,判断是否监听
  • watch中不要使用箭头函数,因为箭头函数中的this未定义,指向外层的对象new Vue({}),实例初始化时,{}这是传的对象,所以箭头函数中的this指向外部的全局对象
<span>{{ test }}</span>
...
data(){
    return {
        test: "测试",
    }
},
watch:{
    test(){
        console.log('test更新了')
    },
    immediate: true,//第一次展示页面时,未设置或设置为false,都不会触发;为true会触发
}

3. computed,watch区别

都是监听数据,

其中computed,计算属性,看上去是一个方法,但是在使用时,是当成属性,不需要加();有缓存,当依赖的数据发生变化时,会自动更新,如果没变化,直接读缓存。

watch 检测数据变化时,会执行对应的回调。选项deep为true时,监听对象内部属性的变化,选项immediate为true时,将立即以表达式的当前值触发回调。

computed 常用于 依赖的数据变化后,更新数据;watch主要侧重于,数据变化后,需要做哪些操作