深刻理解Vue中的watch

更多文章可戳:github.com/MagicalBrid…html

假设有以下代码:git

<div>
  <p>FullName: {{fullName}}</p>
  <p>FirstName: 
    <input type="text" v-model="firstName">
  </p>
</div>
复制代码
new Vue({
  el: '#root',
  data: {
    firstName: 'Dawei',
    lastName: 'Lou',
    fullName: ''
  },
  watch: {
    firstName(newName, oldName) {
      this.fullName = newName + ' ' + this.lastName;
    }
  } 
})
复制代码

上面的代码的效果是,当咱们输入firstName后,watch监听每次修改变化的新值,而后计算出fullNamegithub

handler方法和immediate属性

这里watch的一个特色是,最初绑定的时候是不会执行的,要等到firstName改变的时候才执行监听计算,那咱们想要一开始就让他最初绑定的时候就执行怎么办呢?咱们须要修改一下咱们的watch写法,修改事后的watch代码以下:app

watch:{
    firstName:{
      handler(newName,oldName){
        this.fullName = newName+ ' ' + this.lastName
      },
      // 表明watch里面声明了firstName这个方法以后当即执行handler方法
      immediate: true
    },
   
  }
复制代码

注意到handler了吗?咱们给firstName绑定了一个handler方法,以前咱们写的watch方法其实默认写的就是这个handler,Vue.js会处理这个逻辑,最终编译出来的其实就是这个handler.函数

而immediate:true 表明若是在watch里面声明了firstName以后,就会当即先去执行里面的handler方法,若是为false,就和咱们以前的效果同样,不会再绑定的时候就执行。性能

deep属性

watch里面还有一个属性deep,默认值是 false 表明的是否深度监听,好比咱们data里面有一个obj属性。优化

<div>
  <p>obj.a: {{obj.a}}</p>
  <p>obj.a: 
    <input type="text" v-model="obj.a"><
  </p>
</div>
复制代码
new Vue({
  el: '#root',
  data: {
    obj: {
      a: 123
    }
  },
  watch: {
    obj: {
      handler(newName, oldName) {
        console.log('obj.a changed');
      },
      immediate: true
    }
  } 

})
复制代码

当咱们在输入框中输入数据改变obj.a数据的时候。咱们发现虽然视图更新了,可是在handler回调并无执行,也就没有打印obj.a changed在这里Vue并不能检测到对象的属性的添加或者删除。因为Vue在初始化的时候对于属性执行了getter/setter转化过程,因此属性必须在data对象上存在才能让Vue转换它,这样才能让它是响应式的。ui

默认的状况下,handle只监听obj这个属性它的引用的变化,咱们值有给obj赋值的时候它才会监听到,好比咱们在mounted事件钩子函数中对obj进行从新赋值。这个时候 是能够触发 handler 监听回调的。this

若是咱们想要监听 obj 里的属性a的值呢? 这个时候 deep 属性就派上用场了!spa

watch: {
  obj: {
    handler(newName, oldName) {
      console.log('obj.a changed');
    },
    immediate: true,
    deep:true
  }
} 
复制代码

deep的意思是深刻观察,监听器会一层层的往下遍历,给对象的全部的属性都添加这个侦听器,可是 这样性能开销就会比较大了,任何修改obj里面任何一个属性都会触发这个侦听器里面的handler.

优化,咱们可使用字符串形式进行监听。

watch:{
  'obj.a': {
    handler(newName, oldName) {
      console.log('obj.a changed');
    },
    immediate: true
  }
}
复制代码

使用上述的写法,即便不使用deep属性选项,依然可以成功的触发监听回调。

注销watch

为何要注销watch? 由于咱们的组件是常常要销毁的,好比咱们跳转一个路由,从一个页面跳转另外一个页面。那么原来的页面的watch就没有用了,这个时候咱们应该注销原来页面的watch否则会有一些性能问题,好在咱们平时都是将watch写在组件中的,他会随着组件的销毁而销毁。

const app = new Vue({
  template: '<div id="root">{{text}}</div>',
  data: {
    text: 0
  },
  watch: {
    text(newVal, oldVal){
      console.log(`${newVal} : ${oldVal}`);
    }
  }
});
复制代码

可是,若是咱们使用下面这样的方式写 watch,那么就要手动注销了,这种注销其实也很简单

const unWatch = app.$watch('text', (newVal, oldVal) => {
  console.log(`${newVal} : ${oldVal}`);
})

unWatch(); // 手动注销watch
复制代码

app.$watch调用后会返回一个值,就是unWatch方法,你要注销 watch 只要调用unWatch方法就能够了。

最后谢谢各位小伙伴愿意花费宝贵的时间阅读本文,若是本文给了您一点帮助或者是启发,请不要吝啬你的赞和Star,您的确定是我前进的最大动力。github.com/MagicalBrid…

相关文章
相关标签/搜索