深刻理解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…

相關文章
相關標籤/搜索