咱們都知道在Vue構造函數的參數對象中有一個【data】屬性,該屬性值是一個對象,該對象是對數據的代理,是一個鍵值對而且時刻與頁面表現是一致的,可是這裏面只能是簡單的鍵值對,不能擁有業務邏輯,而且因爲【data】中的屬性屬於同一個生命週期,因此若是咱們須要某一個屬性是依賴於另一個屬性時,在【data】中是作不到的,因而Vue爲咱們提供了【計算屬性】es6
計算屬性歸根結底也是屬性,它也是跟表現層是時刻同步的,雖然咱們能夠在插值中對數據進行各類處理,可是插值中的表達式處理畢竟只能用於簡單的運算,不能擁有太多的業務邏輯。數據庫
<body> <div id="app"> <h1>{{name.toUpperCase()}}</h1> <!-- <h1>BLUE</h1> --> </div> </body> <script> let vm = new Vue({ el: "#app", data: { name: 'blue' } }) </script>
上面代碼是咱們熟悉的在插值中使用表達式,可是這裏面咱們不能寫入業務代碼。數組
在構造函數的參數對象中有一個【computed】屬性,該屬性就是用於定義計算屬性的,該對象中的【鍵】也就是咱們的計算屬性,與【data】不一樣的是,計算屬性的鍵值是一個【擁有返回值的函數】,該函數中能夠訪問到【data】中的全部屬性。緩存
<body> <div id="app"> <h1>{{rs}}</h1> <!-- <h1>BLUE LOVE PINK</h1> --> </div> </body> <script> let vm = new Vue({ el: "#app", data: { hs: 'BLUE', wf: "PINK" }, computed: { rs:function(){ return `${this.hs} LOVE ${this.wf}` } } }) </script>
上面代碼屬性【rs】是定義的一個計算屬性,該屬性值是經過【data】中的兩個屬性值計算獲得,返回一個拼接的字符串(這兒使用了ES6的【模板字符串】)而且當【data】中的相關值變化以後,【rs】屬性都會進行從新計算。app
可能剛開始對計算屬性會有些疑惑,好比上面的例子我把代碼寫成下面這樣子也是能夠的異步
<body> <div id="app"> <h1>{{hs}} LOVE {{wf}}</h1> <!-- <h1>BLUE LOVE PINK</h1> --> </div> </body> <script> let vm = new Vue({ el: "#app", data: { hs: 'BLUE', wf: "PINK" } }) </script>
上面的代碼運行效果和咱們使用計算屬性的效果是同樣的,可是這樣的寫法只適用於簡單的處理,【計算屬性能夠處理更復雜的業務邏輯】,好比咱們根據【data】中的一個屬性值進行數據請求用於構建一個屬性,咱們就必須使用計算屬性了。函數
【注意!!】計算屬性雖然是一個方法,可是在Vue內部會被翻譯成一個屬性,咱們可使用實例【vm.rs】訪問到數據的。性能
若是用於對【data】中【單個】屬性的【簡單】處理,推薦使用過濾器,可是若是一個值使用了【data】中至少2個值或者對一個值進行復雜處理,那麼就推薦使用計算屬性了。this
<body> <div id="app"> <h1>{{hs | lover}}</h1> <!-- <h1>BLUE LOVE PINK</h1> --> </div> </body> <script> let vm = new Vue({ el: "#app", data: { hs: 'BLUE', }, filters: { lover(value){ return `${value} LOVE PINK` } } }) </script>
上面代碼就使用了一個【data】屬性值作簡單的處理,因此使用過濾器,並且也發現了過濾字符串「LOVE PINK」是不可變的。翻譯
計算屬性就是爲了定屬性的時候處理複雜的業務邏輯,並且在插值中咱們可使用表達式,那麼咱們是否能夠經過使用在插值中調用一個有返回值的函數呢?它和計算屬性又有什麼區別呢?
<body> <div id="app"> <h1>{{rs}}</h1> <!-- <h1>EULB</h1> --> </div> </body> <script> let vm = new Vue({ el: "#app", data: { name: 'BLUE', }, computed: { rs: function () { return [...this.name].reverse().join(''); } } }) </script>
上面代碼將數據進行反向處理(使用了【ES6數組字符串擴展】),當咱們改變name的值的時候,計算屬性【rs】會跟着改變。下面咱們將它改爲一個方法結合插值表達式進行處理,看看區別。
<body> <div id="app"> <h1>{{ rs() }}</h1> <!-- <h1>EULB</h1> --> </div> </body> <script> let vm = new Vue({ el: "#app", data: { name: 'BLUE', }, methods: { rs() { return [...this.name].reverse().join(''); } } }) </script>
上面代碼將計算屬性改爲了一個方法結合插值表達式,發現效果和計算屬性沒差異,改變name的值的時候頁面也刷新了。那是否是這二者就真的沒區別呢,答案固然是否認的,若是沒有區別幹嗎還有計算屬性的存在。
【計算屬性是基於依賴進行緩存的】,只有計算屬性的依賴發生改變時纔會從新求值,也就是說若是依賴沒有發生改變,那麼計算屬性會馬上返回以前的計算結果,假如咱們有一個性能開銷比較大的的計算屬性 A ,它須要遍歷一個極大的數組和作大量的計算。而後咱們可能有其餘的計算屬性依賴於 A 。若是沒有緩存,咱們將不可避免的屢次執行 A 的 getter!若是你不但願有緩存,請用 method 替代。
咱們發現計算屬性會監聽依賴,若是依賴發生變化則會重新計算屬性,那麼【監聽器】也有這麼一個功能,那麼咱們應該在何時使用【計算屬性】,何時使用【監聽器】呢?
<body> <div id="app"> <h1>{{fullName}}</h1> </div> </body> <script> let vm = new Vue({ el: "#app", data: { firstName: 'Jack', lastName: 'Blue', fullName: 'Jack Blue' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName }, lastName: function (val) { this.fullName = this.firstName + ' ' + val } } }) </script>
上面代碼中咱們監聽firstName和lastName用於構建fullName,效果很好,當firstName和lastName任意一個值改變的時候fullName都會隨之改變。下面咱們看一下計算屬性的寫法
<body> <div id="app"> <h1>{{fullName}}</h1> <!-- <h1>Jack Blue</h1> --> </div> </body> <script> let vm = new Vue({ el: "#app", data: { firstName: 'Jack', lastName: 'Blue', }, computed: { fullName() { return this.firstName + ' ' + this.lastName } } }) </script>
上面代碼使用計算屬性的方式進行了改造,fullName 依賴 firstName和 lastName 兩個屬性,當這兩個屬性任意一個發生變化,fullname都會從新進行計算。可是計算屬性是否是簡潔了不少呢!
【總結!!】當一個屬性須要依賴多個【data】中的屬性時,建議使用計算屬性,若是咱們不是對屬性進行操做,只是單純的依據【data】中的某個值變化後作一些【非屬性操做】時或者是在數據變化響應時,【執行異步操做或開銷較大的操做】(好比:將變化後的值存入數據庫,而不是改變其餘屬性)就使用Watch。
上面咱們是使用的計算屬性都是用於對計算屬性的取值,計算屬性默認頁只給了【getter】,可是在須要的時候咱們能夠人爲的添加【setter】
<body> <div id="app"> <h1>{{fullName}}</h1> <!-- <h1>Jack Blue</h1> --> </div> </body> <script> let vm = new Vue({ el: "#app", data: { firstName: 'Jack', lastName: 'Blue', }, computed: { fullName: { //getter get() { return this.firstName + ' ' + this.lastName }, //setter set(newValue) { var names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1] } } } }) </script>
上面代碼定義了計算屬性的一個setter,注意當須要定義setter的時候語法上面是有區別的。