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>