這一章主要整理一下vue中computed(計算屬性)和watch(監聽屬性)的用法。
1.computed
computed主要的做的是元數據進行加工返回一個新的數據。
案例一、現在data中有firstName 和lastName兩個值,顯示全名
解決方法一:{{firstName + ' ' + lastName}}
這是最簡單的方法,在計算的數據量比較少的時候可以採用。
解決方法二:computed
var vm = new Vue({
el: "#app",
template: `
<div>
<p>name : {{name}}</p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming"
},
computed: {
name() {
return `${this.firstName} ${this.lastName}`;
}
},
})
解決方法三:methods
var vm = new Vue({
el: "#app",
template: `
<div>
<p>name : {{getName()}}</p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming"
},
methods: {
getName() {
return `${this.firstName} ${this.lastName}`;
}
},
})
可以看到其實方案二和方案三都實現的要求,但是推薦使用方案二,原因主要是:computed只有再依賴的數據發生改變的時候纔會重新計算(緩存機制),而methods在任意數據改變的時候都會重新去計算。
測試案例:
var vm = new Vue({
el: "#app",
template: `
<div>
<p>name1 : {{name}}</p>
<p>name2 : {{getName()}}</p>
<p>number: <input type="text" v-model='number' /> </p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming",
number: 0
},
computed: {
name() {
console.log('recalculate computed')
return `${this.firstName} ${this.lastName}`;
}
},
methods: {
getName() {
console.log('recalculate methods')
return `${this.firstName} ${this.lastName}`;
}
},
})
輸出結果(當在input框中不斷改變number的值)
可以發現,這時候每次number的值改變都會觸發methods中的getName()方法。
computed執行setter操作(不推薦,但是有computed有這個功能)
案例二、輸入全名,然後依據輸入的全名改變data中的firstName和lastName。
var vm = new Vue({
el: "#app",
template: `
<div>
<p>firstName : {{firstName}}</p>
<p>lastName : {{lastName}}</p>
<p>name : <input type="text" v-model='name' /> </p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming",
number: 0
},
computed: {
name: {
get() {
console.log('recalculate computed')
return `${this.firstName} ${this.lastName}`;
},
set(name) {
const names = name.split(' ');
this.firstName = names[0];
this.lastName = names[1];
}
}
}
})
改變輸入框中的name,得到輸出結果:
2.watch
watch是監聽一個值的變化,然後進行一系列的操作。
案例三、還是上面的例子用watch也能實現(比較麻煩,需要監聽firstName和lastName兩個值的變化,不推薦,這裏只是作爲一個例子)。
var vm = new Vue({
el: "#app",
template: `
<div>
<p>firstName : <input type='text' v-model='firstName' /></p>
<p>lastName : <input type='text' v-model='lastName' /> </p>
<p>fullName : {{fullName}}</p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming",
fullName: ''
},
watch: {
firstName(newValue, oldValue) {
this.fullName = newValue + ' ' + this.lastName;
}
}
})
輸出結果:
可以看出剛開始fullName是空的,這是因爲第一次剛渲染完成的時候watch默認是不執行的,改變下firstName輸出結果:
這樣就看到了我們想要的結果,那如果要求第一次渲染的時候就要執行watch,方法如下:
var vm = new Vue({
el: "#app",
template: `
<div>
<p>firstName : <input type='text' v-model='firstName' /></p>
<p>lastName : <input type='text' v-model='lastName' /> </p>
<p>fullName : {{fullName}}</p>
</div>
`,
data: {
firstName: "zhu",
lastName: "Ming",
fullName: ''
},
watch: {
firstName: {
handler(newValue, oldValue) {
this.fullName = newValue + ' ' + this.lastName;
},
immediate: true //即時,即立刻執行的意思。
}
}
})
這樣我們就可以得到第一次渲染的時候 watach方法也執行了 結果:
和上例中的immediate一樣,還有設置deep參數
deep表示監聽深度監聽
案例四、在data中有一個obj對象,需要監聽obj.a的變化
var vm = new Vue({
el: "#app",
template: `
<div>
<p>obj.a : <input type='text' v-model='obj.a' /></p>
<p>obj.b : <input type='text' v-model='obj.b' /></p>
</div>
`,
data: {
obj: {
a: 0,
b: 'a'
}
},
watch: {
obj: {
handler(newValue, oldValue) {
console.log('watch obj.a changed')
},
immediate: false //即時,即立刻執行的意思。
}
}
})
可以看到上例監聽了obj的變化,但是obj.a進行改變的時候,輸出結果:
說明並沒有執行watch下面監聽的函數,這時候上deep:true,再次進行測試,輸出結果:
但是,我們繼續改變obj.b的值,發現監聽又再次觸發了,其輸出結果:
這個說明,一旦加了deep:true的屬性之後,vue會遍歷監聽的obj下面說有值,但其實我們只想要監聽obj.a,而且這樣效率也低下,再次修改:只需要將監聽的obj改成'obj.a'即可
var vm = new Vue({
el: "#app",
template: `
<div>
<p>obj.a : <input type='text' v-model='obj.a' /></p>
<p>obj.b : <input type='text' v-model='obj.b' /></p>
</div>
`,
data: {
obj: {
a: 0,
b: 'a'
}
},
watch: {
'obj.a': {
handler(newValue, oldValue) {
console.log('watch obj.a changed')
},
immediate: false, //即時,即立刻執行的意思。
deep: false
}
}
})
改過之後發現及時deep爲false,但是修改obj.a的時候能正常觸發監聽,改變obj.b的時候無法觸發監聽。
案例四、當在watch的中改變被監聽的值。
可以試想一下,如果監聽obj.a,你又在監聽觸發的方法中改變了obj.a的會造成什麼後果。
ok,這想必大家都知道,那就是死循環,所以千萬不要用。
var vm = new Vue({
el: "#app",
template: `
<div>
<p>obj.a : <input type='text' v-model='obj.a' /></p>
<p>obj.b : <input type='text' v-model='obj.b' /></p>
</div>
`,
data: {
obj: {
a: 0,
b: 'a'
}
},
watch: {
'obj.a': {
handler(newValue, oldValue) {
this.obj.a += 1;
console.log('watch obj.a changed')
},
immediate: false, //即時,即立刻執行的意思。
deep: false
}
}
})
稍稍改變一下a的值,可以看到結果:
上圖結果obj.a的值還爲0是因爲,瀏覽器直接卡崩了。好了,所以千萬不要在watch監聽中去改變本身。