Vue watch選項

呆裡呆氣1發表於2018-01-11

定義

watch 選項是一個物件,鍵是需要觀察的表示式,值是對應回撥函式。Vue 例項將會在例項化時呼叫 $watch(),遍歷 watch 物件的每一個屬性。

用法

watch 物件裡的 value 是對應的回撥函式

data () {
  return {
    a: 1
  }
},
watch: {
  a: function (newVal, oldVal) {
    console.log(newVal, oldVal)
    // 2 1
  }
},
created () {
  this.a = 2
}
複製程式碼

a 的值被改變時,watch 物件中 a 所對應的函式會被呼叫,該函式接收兩個引數,第一個為 a 的 new value,第二個為 a 的 old value。

value 也可以是方法名

data () {
  return {
    a: 1
  }
},
watch: {
  a: 'foo'
},
created () {
  this.a = 2
},
methods: {
  foo (newVal, oldVal) {
    console.log(newVal, oldVal)
    // 2 1
  }
}
複製程式碼

a 的值被改變時,會直接觸發 methods 裡的 foo 方法,該方法同樣接收新值和舊值兩個引數。

深度監聽

物件內部屬性或方法發生改變,須使用深度監聽模式才能監聽到該物件的改變

data () {
  return {
    box: {
      name: 'jordan'
    }
  }
},
watch: {
  box: {
    handler: function (newVal, oldVal) {
      console.log(newVal.name, oldVal.name)
      // kobe kobe
    },
    deep: true  // 深度監聽模式
  }
},
created () {
  this.box.name = 'kobe'
}
複製程式碼

執行程式碼會列印出 kobe kobe,這是因為 box.name 的值更新之後, box 物件的記憶體地址仍然不變,newValoldVal 都指向該地址,值更新觸發 handler 之後列印出兩個更新之後的 name,即 'kobe kobe'

如果去掉 deep: true 將無法監聽到 box 的變化,除非直接給 this.box 賦值,改變 box 指標的指向,這種方式也能拿到 old valuenew value,對應 this.box 指標前後分別指向的 box 物件。

不使用深度監聽時,可以直接監聽 box.name

data () {
  return {
    box: {
      name: 'jordan'
    }
  }
},
watch: {
  'box.name': {
    handler: function (newVal, oldVal) {
      console.log(newVal, oldVal)
      // kobe jordan
    }
  }
},
created () {
  this.box.name = 'kobe'
}
複製程式碼

這時 box.name 又是一個簡單值,所以輸出 'kobe jordan'

陣列的監聽

data () {
  return {
    box: [1, 1, 1]
  }
},
watch: {
  box: {
    handler: function () {
      console.log('watch works')
    }
  }
},
created () {
  this.box[0] = 2
  this.box.length = 4
  this.box.push(1)  // watch works
  this.box.splice(0, 1, 2)  // watch works
}
複製程式碼

created 裡使用了4種方式對 box 進行操作,第一種和第二種方式 watch 是監聽不到的,即便使用深度監聽模式也無法監聽的到,可以參考下這裡

使用 immediate

data () {
  return {
    box: 1
  }
},
watch: {
  box: {
    handler: function () {
      console.log('watch works')
    },
    immediate: true
  }
}

// watch works
複製程式碼

增加 immediate: true 選項,handler 會在偵聽開始之後被立即呼叫,即便 box 的值沒有改變。如果對 this.box 的值加以修改,便會輸出兩次 'watch works',一次是偵聽開始的時候,一次是 box 的值被修改的時候。

watch 裡的 value 可以是放在一個陣列裡面的多個 handler

data () {
  return {
    box: 1
  }
},
watch: {
  box: [
    function foo (newVal, oldVal) {
      console.log(newVal, oldVal)
      // 2 1
    },
    function bar (newVal, oldVal) {
      console.log(newVal, oldVal)
      // 2 1
    }
  ]
},
created () {
  this.box = 2
}
複製程式碼

每一個 handler 都可以接收 new valueold value 兩個引數,並且會按各自在陣列中的順序先後觸發。當然下面的操作也能實現這樣的場景。

data () {
  return {
    box: 1
  }
},
watch: {
  box: function (newVal, oldVal) {
    this.foo(newVal, oldVal)
    this.bar(newVal, oldVal)
  }
},
created () {
  this.box = 2
},
methods: {
  foo (newVal, oldVal) {
    console.log(newVal, oldVal)
  },
  bar (newVal, oldVal) {
    console.log(newVal, oldVal)
  }
}
複製程式碼

不應該使用箭頭函式來定義 watcher 函式

data () {
  return {
    box: 1
  }
},
watch: {
  box: newVal => {
    this.updateBox(newVal)
  }
},
created () {
  this.box = 2
},
methods: {
  updateBox (newVal) {
    this.box = newVal
  }
}
複製程式碼

上面的例子會報錯,是因為箭頭函式繫結了父級作用域的上下文,所以 this 將不會指向 Vue 例項,也就沒有 this.updateBox 這個方法,可以參考ES6箭頭函式 this指向

相關文章