前言
在vue項目中,數(shù)據(jù)和視圖是可以實現(xiàn)雙向綁定的,修改數(shù)據(jù),視圖隨之改變护桦,反之亦然乙濒。在許多業(yè)務(wù)場景中,我們需要針對視圖數(shù)據(jù)的改變做出相應(yīng)的響應(yīng)操作,這個時候就需要用到vue提供的watch監(jiān)聽機(jī)制。
先給出一個簡單的應(yīng)用示例(以下為vue文件)
<template>
<div id="bestRecommendMainPage">
<p>
<label>當(dāng)前板塊:</label>
<input type="text" v-model="msg">
</p>
<button @click="changeName()">更新</button>
</div>
</template>
<script>
export default {
data() {
return {
msg: "精品書樓"
};
},
watch: {
msg(newValue, oldValue) {
console.log(`監(jiān)聽到值發(fā)生變化:${newvalue}`);
}
},
methods: {
changeName() {
this.msg = this.msg + '-'
}
}
};
</script>
執(zhí)行上述代碼我們會發(fā)現(xiàn),不管是手動修改輸入框內(nèi)的值舱沧,還是點擊按鈕代碼修改msg的值,每當(dāng)msg的值被修改偶洋,都會觸發(fā)watch監(jiān)聽熟吏,打印出對應(yīng)的修改后的新值。
immediate屬性
如果細(xì)心會發(fā)現(xiàn),上述中watch中并沒有監(jiān)聽到msg的初始值:精品書樓牵寺。這就涉及到了watch的一個特點即:默認(rèn)情況下在data數(shù)據(jù)初始化的時候是不被監(jiān)聽的悍引,只有當(dāng)后續(xù)值發(fā)生變化時,才能監(jiān)聽到帽氓。
那么如果我們一定要初始化時就被監(jiān)聽到的話趣斤,我們就可以在watch中設(shè)置一個immediate屬性,故名思意就是即刻觸發(fā)監(jiān)聽的意思黎休,這里也需要用到watch監(jiān)聽的完整寫法:
<script>
export default {
data() {
return {
msg: "精品書樓"
};
},
watch: {
msg: {
handler(newvalue,oldvalue) {
console.log(`監(jiān)聽到值發(fā)生變化:${newvalue}`);
},
immediate: true, //該屬性是指data數(shù)據(jù)初始化時即對其中數(shù)據(jù)進(jìn)行監(jiān)聽浓领,mounted中對data數(shù)據(jù)的修改不屬于該屬性范圍
deep: true
},
},
};
</script>
上面代碼中的handler方法就是監(jiān)聽到數(shù)據(jù)變化后需要執(zhí)行后續(xù)處理的函數(shù),immediate為true時势腮,就代表在watch里聲明了msg后联贩,就會立即去執(zhí)行其handler里面的方法,常見的一個適用場景就是父組件向子組件傳值時,需要首次傳入就執(zhí)行監(jiān)聽捎拯。第一個示例就是該寫法的簡易寫法泪幌。
deep屬性
了解了immediate屬性后,我們注意到上面代碼中有一個deep屬性玄渗,這個屬性是做什么的呢座菠?這涉及到了watch監(jiān)聽機(jī)制中的一個深度監(jiān)聽問題狸眼,我們知道上面示例中監(jiān)聽的只是一個變量屬性藤树,那么如果我們監(jiān)聽的是一個對象屬性呢?類似下面的示例:
<template>
<div id="bestRecommendMainPage">
<p>
<label>隨機(jī)數(shù)值一:</label>
<input type="text" v-model="obj.a">
</p>
<button @click="changeNum()">漸增數(shù)值</button>
</div>
</template>
<script>
export default {
data() {
return {
obj: { a: 2 }
};
},
watch: {
obj: {
handler(newvalue) {
console.log(`監(jiān)聽到值發(fā)生變化:${newvalue.a}`);
},
immediate: true
}
},
methods: {
changeNum() {
++this.obj.a;
}
}
};
這個時候不論是更新視圖中的輸入數(shù)據(jù)拓萌,還是直接代碼中更新數(shù)據(jù)obj.a的值岁钓,watch都是監(jiān)聽不到的。受javascript的限制微王,VUE不能檢測到對象屬性的添加和刪除屡限,VUE會在初始化實例時對data內(nèi)的屬性執(zhí)行g(shù)etter/setter轉(zhuǎn)化過程,也就是說必須是data的屬性才能執(zhí)行該轉(zhuǎn)化炕倘,這里只有改變obj的引用才能被監(jiān)聽到钧大,比如在mounted鉤子函數(shù)中為其重新賦值,這樣才會被監(jiān)聽到罩旋。示例如下
mounted() {
this.obj = { a: 12 };
},
但這樣并不能解決我們的進(jìn)一步需求啊央,如果要監(jiān)聽obj對象中的屬性變化,要怎么實現(xiàn)涨醋?很簡單瓜饥,設(shè)置deep屬性為true即可。示例如下:
watch: {
obj: {
handler(newvalue) {
console.log(`監(jiān)聽到值發(fā)生變化:${newvalue.a}`);
},
immediate: true,
deep: true
}
},
deep屬性所起的作用是這樣的:它會一層層的向下遍歷浴骂,給對象的所有屬性(也可以是二級三級的)添加監(jiān)聽乓土。但這樣也會產(chǎn)生一個問題:性能開銷過大,對象中任意屬性的改變都會觸發(fā)監(jiān)聽里面的handler方法。所以如果只是針對對象中的某個屬性的話趣苏,可以有兩種處理方法:
一狡相、利用computed計算屬性拦键,將要監(jiān)聽的對象屬性生成一個新屬性,繼而監(jiān)聽這個新屬性芬为。
二萄金、優(yōu)化監(jiān)聽方式媚朦,采用字符串形式(與方法一是一個意思)
"obj.a": {
handler(newvalue) {
console.log(`監(jiān)聽到值發(fā)生變化(字符串格式):${newvalue}`);
}
},
這里要注意的一點時,此時的newValue就是obj.a的新值询张,而不是obj的值。