1 監視屬性¶
監視屬性是一種用於監視某個資料的變化,並觸發相應的回撥函式執行的機制。在vue內部,使用“wathch”關鍵字用於宣告監視屬性。
1.1 基本用法¶
(1)新增watch屬性,值為一個物件。物件的屬性名就是要監視的資料,屬性值為回撥函式,每當這個屬性名對應的值發生變化,就會觸發該回撥函式執行
(2)回撥函式有2個引數:
newVal:資料發生改變後的值
oldVal:資料發生改變前的值
例如,我們定義一個變數num,在頁面中新增一個按鈕,每點選一次按鈕,num的值加1,另外,每次在num的值發生改變時,控制檯輸出提示。
<!-- 準備好一個容器-->
<div id="root">
<h2>num的值為:{{num}}</h2>
<button @click="changeNum">點選num+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在啟動時生成生產提示。
const vm = new Vue({
el:'#root',
data:{
num: 0
},
methods: {
changeNum(){
this.num = this.num + 1
}
},
watch:{
num(newVal, oldVal){ // newVal為修改後的值, oldVal為修改前的值
console.log('num的值發生了變化')
console.log(newVal,oldVal)
}
}
})
</script>
1.2 監聽物件內部屬性的變化¶
前面的例子只是監聽data中的第一層資料,如果要監聽多層次的資料,例如a.b.c,則屬性名需要用引號包裹起來.
<div id="root">
<h2>a的值為:{{num.a}}</h2>
<h2>num的值為:{{num}}</h2>
<button @click="changeA">點選a+1</button>
<button @click="changeNum">修改num</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在啟動時生成生產提示。
const vm = new Vue({
el:'#root',
data:{
num: {
a: 0,
b: 0
}
},
methods: {
changeA(){
this.num.a = this.num.a + 1
},
changeNum(){
this.num = {a:100, b:200}
}
},
watch:{
"num.a"(newVal, oldVal){ // 注意:此時,因為a是物件內部變數,所以a必須用“num.a”的方式用雙引號包裹
console.log('a的值發生了變化')
console.log(newVal,oldVal)
},
num(newVal, oldVal){ // newVal為修改後的值, oldVal為修改前的值
console.log('num的值發生了變化')
console.log(newVal,oldVal)
}
}
})
</script>
如下圖所示,第一次點選“點選a+1”按鈕,a的值加了1,控制檯輸出了兩行;第一次點選“修改num”按鈕,因為a的值也同時發生改變,所以a的監視屬性也觸發,因為num完整修改了,所以,num的監視屬性也修改了。所以會有4行輸出結果在控制檯。
1.3 深度監聽¶
監視屬性只能監聽到當前物件值的變化,而物件內部的屬性變化不會監聽到,前面1.2節我們監聽了num和num.a,修改了num.a並不會觸發監聽num的監聽屬性。 想要監聽物件內部的屬性值變化,需要進行相應的配置。
-
deep:深度監聽,預設false,當物件內部深層屬性變數發生修改時,是否觸發
-
handler:回撥函式
-
immediate: 頁面初始化時是否觸發回撥,預設false
如下所示,我們只監聽num物件,但修改num物件內部的變數a時,num的監聽屬性也被觸發,這就是深度監聽的作用:
<div id="root">
<h2>a的值為:{{num.a}}</h2>
<button @click="changeA">點選a+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在啟動時生成生產提示。
const vm = new Vue({
el:'#root',
data:{
num: {
a: 0,
b: 0
}
},
methods: {
changeA(){
this.num.a = this.num.a + 1 // 注意:此處修改的是a的值,而不是整個num
}
},
watch:{
num: { // 監聽num物件
deep: true, // 深度監聽
handler:function(newVal,oldVal){ // 監聽屬性的回撥方法
console.log('num的值發生了變化')
console.log(this.num.a, this.num.b)
},
immediate:true // 頁面初始化時是否觸發回撥
}
}
})
</script>
點選一次按鈕,控制檯輸出兩次,第一次是因為imediate設定為了true,當頁面初始化時,會自動出發一次num的監視屬性,第一次是點選按鈕觸發。
1.4 監視屬性的簡寫¶
在1.3節說到,監視屬性有三種屬性,即deep、imediate、handler,當deep和imediate兩個屬性不需要使用(使用預設值時),可以使用簡寫形式,下方程式碼中,被註釋的完整形式和簡寫形式作用是一樣的:
<div id="root">
<h2>a的值為:{{num}}</h2>
<button @click="changeNum">點選a+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在啟動時生成生產提示。
const vm = new Vue({
el:'#root',
data:{
num: 0
},
methods: {
changeNum(){
this.num = this.num + 1 // 注意:此處修改的是a的值,而不是整個num
}
},
watch:{
// 完整寫法
// num: { // 監聽num物件
// deep: false, // 深度監聽
// immediate:false,
// handler:function(newVal,oldVal){ // 監聽屬性的回撥方法
// console.log('num的值發生了變化')
// console.log(newVal,oldVal)
// },
// }
// 簡寫形式
num(newVal,oldVal){
console.log('num的值發生了變化')
console.log(newVal,oldVal)
}
}
})
</script>
1.5 建立監視屬性的另一種方式¶
監視屬性也可以在建立完vue例項之後再新增:
<div id="root">
<h2>a的值為:{{num}}</h2>
<button @click="changeNum">點選a+1</button>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在啟動時生成生產提示。
const vm = new Vue({
el:'#root',
data:{
num: 0
},
methods: {
changeNum(){
this.num = this.num + 1 // 注意:此處修改的是a的值,而不是整個num
}
},
})
// 為num新增監視屬性
vm.$watch('num',{ // 指定監視num
immediate:true, //初始化時讓handler呼叫一下
handler(newValue,oldValue){
console.log('num被修改了',newValue,oldValue)
}
})
</script>
2 計算屬性與監視屬性的對比¶
- 計算屬效能完成的功能,監視屬性都能完成
- 監視屬效能完成的部分功能,計算屬性不一定能完成,例如涉及非同步操作的功能
- 如果兩者都能完成的功能,建議使用計算屬性,效率更高
如下所示,連個輸入框分別雙向繫結兩個變數:num1和num2,在輸入框下方輸出兩個變數的和,要求無論哪個變數發生修改,延遲3秒後,再求和並輸出。因為涉及的延遲輸出,計算屬性就不能完成了,這時候要使用監視屬性:
<div id="root">
num1:<input type="text" v-model="num1"> <br/><br/>
num2:<input type="text" v-model="num2"> <br/><br/>
sum:<span>{{sum}}</span> <br/><br/>
</div>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在啟動時生成生產提示。
const vm = new Vue({
el:'#root',
data:{
num1: 0,
num2: 0,
sum: 0
},
watch:{
num1(val){
setTimeout(()=>{
console.log(this)
this.sum = parseInt(this.num1) + parseInt(this.num2)
},3000);
},
num1(val){
setTimeout(()=>{
console.log(this)
this.sum = parseInt(this.num1) + parseInt(this.num2)
},3000);
},
}
})
</script>