定義
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
物件的記憶體地址仍然不變,newVal
和 oldVal
都指向該地址,值更新觸發 handler
之後列印出兩個更新之後的 name
,即 'kobe kobe'
。
如果去掉 deep: true
將無法監聽到 box
的變化,除非直接給 this.box
賦值,改變 box
指標的指向,這種方式也能拿到 old value
和 new 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 value
和 old 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指向。