前言
一般情況下屬性都是放到data
中的,但是有些屬性可能是需要經過一些邏輯計算後才能得出來,那麼我們可以把這類屬性變成計算屬性。比如以下:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
在這個地方,模板不再是簡單的宣告式邏輯。你必須看一段時間才能意識到,這裡是想要顯示變數 message
的翻轉字串。當你想要在模板中的多處包含此翻轉字串時,就會更加難以處理。
所以,對於任何複雜邏輯,你都應當使用計算屬性。
基礎例子
<div id="app">
<h2>總價格:{{totalPrice}}</h2>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
message: "hello",
books: [
{name: '三國演義', price: 30},
{name: '紅樓夢', price: 40},
{name: '西遊記', price: 50},
{name: '水滸傳', price: 60},
],
},
computed: {
// 計算屬性的 getter
totalPrice: function (){
let result = 0;
// `this` 指向 vm 例項
for (let book of this.books){
result += book.price;
}
return result
}
}
})
</script>
結果:總價格:180
這裡我們宣告瞭一個計算屬性 totalPrice
。然後通過for迴圈計算出書的總價,像這種需要計算的屬性,就寫在computed
中。
屬性一般都有get
和set
兩個方法,get
獲取屬性值,set
設定屬性值,computed
中預設就是get
屬性,我們的vm.totalPrice
是依賴於books.price
,如果書本的價格發生變化,那麼計算屬性totalPrice
也隨之動態變化
計算屬性快取 vs 方法
你可能已經注意到我們可以通過在表示式中呼叫方法來達到同樣的效果:
<div id="app">
<h2>總價格:{{getAllPrice()}}</h2>
</div>
<script>
const vm = new Vue({
el: "#app",
data: {
message: "hello",
books: [
{name: '三國演義', price: 30},
{name: '紅樓夢', price: 40},
{name: '西遊記', price: 50},
{name: '水滸傳', price: 60},
],
},
methods: {
getAllPrice: function () {
let result = 0;
// `this` 指向 vm 例項
for (let book of this.books){
result += book.price;
}
return result
}
},
})
</script>
我們可以將同一函式定義為一個方法而不是一個計算屬性。兩種方式的最終結果確實是完全相同
的。然而,不同的是計算屬性
是基於它們的響應式依賴進行快取
的。只在相關響應式依賴發生改變時它們才會重新求值
。這就意味著只要 books
還沒有發生改變,多次訪問 totalPrice
計算屬性會立即返回之前的計算結果,而不必再次執行函式。
所以說計算屬性是有快取的
我們為什麼需要快取?假設我們有一個效能開銷比較大的計算屬性 A,它需要遍歷一個巨大的陣列並做大量的計算。然後我們可能有其他的計算屬性依賴於 A。如果沒有快取,我們將不可避免的多次
執行 A 的 getter
!如果你不希望有快取,請用方法來替代。
計算屬性的 setter
計算屬性預設只有 getter
,不過在需要時你也可以提供一個 setter
:
computed: {
totalPrice: {
get: function () {
let result = 0;
// `this` 指向 vm 例項
for (let book of this.books){
result += book.price;
}
return result
},
set: function (newValue) {
for (let book of this.books){
book.price += 10
}
}
}
}
這裡我們新增了set
方法,在執行vm.totalPrice=[...]
時,setter
會被呼叫,隨後書本的總價格也會隨之變化,但是一般情況下不會使用set