1. 程式人生 > >Vue(二) 計算屬性

Vue(二) 計算屬性

模板內的表示式常用於簡單的運算,當過長或邏輯複雜時,難以維護,計算屬性就是解決該問題的

什麼是計算屬性

表示式如果過長,或邏輯更為複雜,就會變得臃腫甚至難以維護,比如:

<div>
    {{ text.split('.').reverse().join('.') }}
</div>

該表示式包含 3 個操作,並不是很清晰,可以用計算屬性進行改寫:

<div id="app">
    {{ reverseText }}
</div>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            text: '123,456'
        },
        computed: {
            reverseText: function () {
                //這裡的 this 是當前的 Vue 例項
                return this.text.split(',').reverse().join(',');
            }
        }
    })
</script>

所有的計算屬性都以函式的形式寫在 Vue 例項內的 computed 選項內,最終返回計算結果。

計算屬性的用法

除了上例簡單的用法,計算屬性還可以依賴多個 Vue 例項的資料。只要其中任一資料變化,計算屬性就會重新執行,檢視也會更新。例如,下面的例項是在展示購物車內兩個包裹的總價。

<div id="app">
    {{ prices }}
</div>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            package1: [
                {
                    name: 'iphone xs max',
                    price: 9999,
                    count: 2
                },
                {
                    name: 'ipad pro',
                    price: 6666,
                    count: 2
                }
            ],
            package2: [
                {
                    name: 'apple',
                    price: 20,
                    count: 20
                },
                {
                    name: 'orange',
                    price: 18,
                    count: 20
                }
            ]
        },
        computed: {
            prices: function () {
                var prices = 0;
                for(var i = 0; i < this.package1.length; i++) {
                    prices += this.package1[i].price * this.package1[i].count;
                }
                for(var i = 0; i < this.package2.length; i++) {
                    prices += this.package2[i].price * this.package2[i].count;
                }
                return prices;
            }
        }
    })
</script>

當 package1 和 package2 中的商品有任何變化時,比如購買數量變化或增刪商品時,計算屬性 prices 就會自動更新,檢視中的 prices 也會自動變化。

geter 和 setter

每一個計算屬性都包含一個 getter 和一個 setter,上面的兩個例子都是計算屬性的預設用法,只是利用了 getter 來讀取,在你需要時,也可以提供一個 setter 函式,當手動修改計算屬性的值時就會觸發 setter 函式,執行一些自定義操作,例如:

<div id="app">
    {{ fullName }}
</div>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            firstName: 'Jack',
            lastName: 'Green'
        },
        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];
                }
            }
        }
    })
</script>

當在瀏覽器的控制檯執行 app.fullName = 'John Doe'; 時,setter 就會被呼叫,資料 firstName 和 lastName 都會相對更新,檢視也會更新。

絕大多數情況下,我們只會用預設的 getter 方法來讀取一個計算屬性,在業務中很少用到 setter,因此在宣告一個計算屬性時,直接使用預設的方法即可,不必將 getter 和 setter 都宣告。

計算屬性除了上述簡單的文字插值外,還經常用於動態地設定元素的樣式名稱 class 和內聯樣式 style。當使用元件時,計算屬性也常用於動態傳遞 props。

計算屬性還有兩個很實用的小技巧:一個計算屬性可以依賴其他的計算屬性;二是計算屬性不僅可以依賴當前 Vue 例項的資料,還可以依賴其他例項的資料。

計算屬性快取

在上一篇介紹指令和時間時,你可能發現呼叫 methods 裡的方法也可以與計算屬性起到同樣的作用,比如本章第一個示例可以用 methods 改寫為:

<div id="app">
    {{ reverseText() }}
</div>
<script>
    var app = new Vue({
        <!-- 注意:這裡的 reverseText 是方法,所以要帶() -->
        el: '#app',
        data: {
            text: '123,456'
        },
        methods: {
            reverseText: function () {
                //這裡的 this 是當前的 Vue 例項
                return this.text.split(',').reverse().join(',');
            }
        }
    })
</script>

沒有使用計算屬性,在 methods 裡定義了一個方法實現了相同的效果,甚至該方法還可以接受引數,使用起來更靈活。那為什麼還需要計算屬性呢?原因就是計算屬性是基於它的依賴快取的,一個計算屬性所依賴的的資料發生變化時,它才會重新取值,所以 text 只要不改變,計算屬性也就不更新,例如:

computed: {
    now: function() {
        return Date.now();
    }
}

這裡的 Dtae.now() 不是響應式依賴,所以計算屬性 now 不會更新。但是 methods 則不同,只要重新渲染,它就會被呼叫,因此函式也會被執行。

使用計算屬性還是 methods 取決於你是否需要快取,當遍歷大陣列和大量計算時,應當使用計算屬性,除非你不希望得到快取。