Vue.js: 計算屬性 Computed

計算屬性 Computed

如果在模版內加入太多的邏輯運算,不但顯得雜亂也難以維護。

例如:在顯示預設的字串「Hello World!」之下,再顯示反轉後的字串。

Vue.js - 計算屬性 (Computed)

<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。

Vue.js - 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。在一開始的時候,看不出任何差異。

Vue.js - Computed vs 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 是方法,無論是否有相依,只要有變動都會重新計算。

Vue.js - Computed vs Method

vm.message = '999';

因此

比較 Computed 與 Watch

如下例,使用 computed 或 watch 皆可得到同樣的效果,但 computed 會是一個更好的選擇-更精簡易懂。

使用 computed 的 fullName 取得全名 (姓 + 名)。初始值會自動計算,且若任一相依資料 (firstName 或 lastName) 有變動時重新計算。

使用 watch 觀察 firstName 或 lastName 是否更動,若改變則重新取得 fullNameCombined 的值。fullNameCombined 初始值需手動設定。

Vue.js - Computed 與 Watch

<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

以上參考 Computed Properties and Watchers — Vue.js


vue.js vue.js computed