你真的了解vue2中的watch的工作流程么?

1,124 阅读2分钟

本文要讲什么?

vue2复杂项目中的watch的使用经验。(如有不对的地方,欢迎朋友们指导)

适合谁看?

适合vue2的初,中级学习人群,维护着vue2老项目的开发朋友。

为什么要写本篇文章?

小编发现在维护vue2项目的过程中,发现对watch的理解好像并不怎么深刻,对他们的工作流程并不能有特别清晰的认识,比如说watch会在组件初始化的时候就执行么?watch监听一个对象的时候,当给这个对象添加一个新属性的时候,会触发watch么?等等还有好多类似我不能给出一个准确答案的的问题,所以今天小编下定决心要把这些问题画上一个句号,如果你也对这些问题感兴趣,下面请跟着我一起来看看吧!

watch的一些疑惑问题

watch会在初始化的时候就执行么?

watch监听一个对象的时候,不管你在html模板中是否引用这个对象,当组件初始化渲染的时候,如果你没有在渲染过程中改变这个对象的引用,都不会触发watch的。在项目中类似的情况是这样,在data中定义一个对象,然后在渲染的时候请求接口,将接口返回的数据赋值给这个对象。这时候watch会监听到这个对象发生变化的,因而会触发watch里的回调函数。

watch如果不加deep深度监听的话,还能监听到哪些数据变化?

当我们watch一个对象的时候,如果不加deep为true的时候,其实这个watch能监听到的数据变化非常有限。

<template>
  <div style="margin-left: 20px">
    <lk-button @click="handleClick">点击</lk-button>
  </div>
</template>
<script>
watch: {
    testobj: {
      handler() {
        console.log('testobj-changed');
      },
    }
},
data() {
    return {
      testobj: {
        a: 1
      },
    };
  },
methods: {
    handleClick() {
      this.testobj.b = 2; // 第一种
      this.$set(this.testobj, 'b', 2); // 第二种
      this.testobj = {}; // 第三种
      this.testobj.a = 2; // 第四种
      console.log(this.testobj);
    }
  },
  </script>

现象: 假设上面代码是这样,如果我在点击一个按钮的时候给testobj对象添加一个b属性,按照上面handleClick方法中第一种赋值的话,是触发不了watch的。但是第二种的方法是可以触发watch的。如果按照第三种的赋值,是一定会触发watch的。第四种的赋值,即使a属性已经在data中对象里存在,且a是具备响应性的,但是在点击方法中重新给a赋值的话也是无法触发watch的。

疑问和思考:出现上述这种现象,我对watch的理解可能就有点疑惑了,因为如果不加deep的话,我不使用响应式set方法给对象新加任何属性或者更改已有属性的值都不会触发watch,但是一旦使用响应式set给对象新加属性的话,watch就可以触发,我猜想是$set可能对该对象重新包装了下,使得这个对象的引用发生了变化,所以watch才可以触发。

watch加上deep的话会监听到哪些数据变化?

<template>
  <div style="margin-left: 20px">
    <lk-button @click="handleClick">点击</lk-button>
  </div>
</template>
<script>
watch: {
    testobj: {
      handler() {
        console.log('testobj-changed');
      },
      deep: true
    }
  },
data() {
    return {
      testobj: {
        a: 1,
      },
      b: 2,
    };
  },
handleClick() {
      this.testobj.a = this.b++; // 第一种
      this.testobj.a = 2; // 第二种
      this.testobj.a = {}; // 第三种
      this.testobj.b = 2; // 第四种
      this.$set(this.testobj, 'b', this.b++); // 第五种
      // this.$set(this.testobj, 'a', 2);
      // this.$set(this.testobj, 'a', 2);
      // this.testobj.a = {};
      // Object.defineProperty(this.testobj, 'b', {
      //   value: 2
      // });
      console.log(this.testobj);
    }
</script>

现象:
当watch使用deep的时候,对在data中已经定义的属性a,当在handleClick方法中使用第一种和第三种赋值的时候,会一直触发watch回调。在使用第二种赋值的时候,只会触发一次回调。
当使用第四种方式赋值的时候,不会触发watch。使用第五种的时候,会一直触发watch。
思考和结论:
watch只能监听响应式属性的变化,当这个属性是响应式的时候,一旦这个属性值发生变化,并且属性值是简单数据类型的话,比如number,string,当值改变的时候就会触发watch。如果变化前后的值一样,则不会再触发watch。响应式属性包含使用$set设置的属性。