# Vue.js 學習旅程Mile 11 – Computed 計算屬性篇 ###### tags: `w3HexSchool` `Vue` `Javascript` ## 基本用法 ```htmlmixed= <div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div> ``` ```javascript= var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { // a computed getter reversedMessage: function () { // `this` points to the vm instance return this.message.split('').reverse().join('') } } }) ``` computed 內的 reversedMessage function 就是一個 getter method,每當 message 的值有變化時,便重新計算把值存回 reversedMessage ## 計算屬性特性 ### 具 function 運算能力 的 data 屬性 * 每個對應的計算屬性都是一個具有回傳值且沒有傳入參數的 function 。 * 在模板中直接以 function 名稱設置,不用加 ( ) ### 跟著來源資料變化 * 這個來源資料之一必要是來自 Vue 實例內的 data,才能做響應式依賴。 * 資料變動時,掃 virtual DOM,看哪裡需要更動做修改。 * 沒有 DOM 就沒有 virtual DOM,有 DOM 資料才能做連動。 ### 將結果暫存 * 有暫存機制(cache),若來源資料沒有變化的話,便不會執行方法。 ### getter & setter computed 預設只有 getter 屬性,但也可以經由以下方法重設 setter 屬性。 ```htmlmixed= <div id="app"> <p>fullName (computed):{{ fullName }}</p> </div> ``` ```javascript= computed: { fullName: { // getter get: function () { return this.firstName + ' ' + this.lastName }, // setter set: function (newValue) { var names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1] } } } ``` 當再次運行 vm.fullName = 'John Doe' 時,setter 會被調用,vm.firstName 和 vm.lastName 也會相對應地被更新。 更多關於 getter 和 setter 的知識可以參考這篇文章:[那些關於 Vue 的小細節 - Computed 中 getter 和 setter 觸發的時間點](https://pjchender.blogspot.com/2017/05/vue-computed-getter-setter.html) ## 與 Methods 的不同 使用 methods 改寫上例,也能得到相同的效果。 ```htmlmixed= <p>Reversed message: "{{ reverseMessage() }}"</p> ``` ```javascript= methods: { reverseMessage: function () { return this.message.split('').reverse().join('') } } ``` 不同的是,computed 是根據相依的資料改變時才做計算,而 method 是不管有無相依都會計算,只要每次重新渲染畫面就會執行一次。 ### 使用 Date.now() 的陷阱 ```htmlmixed= <div id="app"> <p>message:{{ message }}</p> <p>now (computed):{{ now }}</p> <p>getNow (method):{{ getNow() }}</p> </div> ``` ```javascript= var vm = new Vue({ el: '#app', data: { message: 'Hello World!', }, computed: { now: function() { return Date.now(); }, }, methods: { getNow: function() { return Date.now(); }, }, }); ``` 在一開始都會執行 computed 和 methods 的時候,沒有任何差異。 ![](https://i.imgur.com/XScJpin.png) 當改變 message 時,由於 now 這個計算屬性沒有用到任何相依的資料,因此不重新計算取值;但 getNow 是方法,無論是否有相依,只要有變動都會重新計算。 ![](https://i.imgur.com/ntPEWys.png) ## 與 Watch 的不同 ```htmlmixed= <div id="demo">{{ fullName }}</div> ``` 使用 watch ```javascript= var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } } }) ``` 使用 computed ```javascript= var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar' }, computed: { fullName: function () { return this.firstName + ' ' + this.lastName } } }) ``` 使用 watch:多了一個 fullName 屬性,而且其相依的屬性有幾個,就得多幾個 watcher 監聽。 ## 使用 computed 時機 * 需要資料產生資料時 * 為了達到更好效能,不需要每次更新方法時 ## 參考資料 * [Vue.js - Computed Properties and Watchers](https://vuejs.org/v2/guide/computed.html) * [Vue.js: 計算屬性 Computed](https://cythilya.github.io/2017/04/15/vue-computed/) * [Vue.js Core 30天屠龍記(第7天): 計算屬性](https://ithelp.ithome.com.tw/articles/10203948)