Vue.js: 計算屬性 Computed
15 Apr 2017計算屬性 Computed
如果在模版內加入太多的邏輯運算,不但顯得雜亂也難以維護。
例如:在顯示預設的字串「Hello World!」之下,再顯示反轉後的字串。
<div id="app">
<p>原始訊息:${ message }</p>
<p>反轉訊息:${ message.split('').reverse().join('') }</p>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
message: 'Hello World!',
},
});
// 由於部落格會把雙花括號的內容吃掉,因此設定 delimiters 以顯示完整程式碼。
如程式碼所示,將反轉的邏輯寫在樣版裡面。這看起來似乎把樣版弄得很髒亂(有潔癖?),基於凡是要切乾淨,未來才好維護的理由,應該要把邏輯寫在一個可以純粹做計算的地方-計算屬性 (computed)。
改寫成這樣…
<div id="app">
<p>原始訊息:${ message }</p>
<p>反轉訊息:${ reversedMessage }</p>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
message: 'Hello World!',
},
computed: {
reversedMessage: function() {
return this.message
.split('')
.reverse()
.join('');
},
},
});
是不是看起來清爽很多!?
computed 內的 reversedMessage 的 function 內容,將成為 reversedMessage 的 getter method,每當 message 的值有變化時,便重新計算 reversedMessage。
意即,computed 會將結果暫存起來,當參考到的資料改變時,computed 才會重新計算。
getter
computed 覆寫 getter,但也可以經由以下方法重設 setter。
<div id="app">
<p>fullName (computed):${ fullName }</p>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
firstName: 'Bill',
lastName: 'Chen',
},
computed: {
fullName: {
get: function() {
return this.firstName + ' ' + this.lastName;
},
set: function(newValue) {
var name = newValue.split(' ');
this.firstName = name[0];
this.lastName = name[name.length - 1];
},
},
},
});
取出 lastName 的值,得到「Chen」。
vm.lastName; //Chen
一但更改 fullName,也會重新設定 firstName 和 lastName 的值。
vm.fullName = 'Gary Lu'; //更改 fullName 的值
vm.lastName; //Lu,重新設定 lastName 的值
比較 Computed 與 Method
使用 method 改寫上例,也能得到相同的效果。
<div id="app">
<p>原始訊息:${ message }</p>
<p>反轉訊息:${ reversedMessage() }</p>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
message: 'Hello World!',
},
methods: {
reversedMessage: function() {
return this.message
.split('')
.reverse()
.join('');
},
},
});
不同的是,computed 是根據相依的資料改變時才做計算,而 method 是不管有無相依都會計算。
如下,now 是計算屬性,getNow 是 method。在一開始的時候,看不出任何差異。
<div id="app">
<p>message:${ message }</p>
<p>now (computed):${ now }</p>
<p>getNow (method):${ getNow() }</p>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
message: 'Hello World!',
},
computed: {
now: function() {
return Date.now();
},
},
methods: {
getNow: function() {
return Date.now();
},
},
});
當改變 message 時,由於 now 這個計算屬性沒有用到任何相依的資料,因此不重新計算取值;但 getNow 是方法,無論是否有相依,只要有變動都會重新計算。
vm.message = '999';
因此
- 需要每次更新,就用 method
- 在意效能,就用 computed
比較 Computed 與 Watch
如下例,使用 computed 或 watch 皆可得到同樣的效果,但 computed 會是一個更好的選擇-更精簡易懂。
使用 computed 的 fullName 取得全名 (姓 + 名)。初始值會自動計算,且若任一相依資料 (firstName 或 lastName) 有變動時重新計算。
使用 watch 觀察 firstName 或 lastName 是否更動,若改變則重新取得 fullNameCombined 的值。fullNameCombined 初始值需手動設定。
<div id="app">
<p>fullName (computed):${ fullName }</p>
<p>fullNameCombined (watch):${ fullNameCombined }</p>
</div>
var vm = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
firstName: 'Bill',
lastName: 'Chen',
fullNameCombined: 'Bill Chen',
},
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName;
},
},
watch: {
firstName: function(val) {
this.fullNameCombined = this.firstName + ' ' + this.lastName;
},
lastName: function(val) {
this.fullNameCombined = this.firstName + ' ' + this.lastName;
},
},
});
關於 watch 請見 Vue.js: Watch。