3. Vue語法--計算屬性

盛開的太陽發表於2021-02-20

一. 計算屬性

1. 什麼是計算屬性?

通常, 我們是在模板中, 通過插值語法顯示data的內容, 但有時候我們可能需要在{{}}裡新增一些計算, 然後在展示出來資料. 這時我們可以使用到計算屬性

先來舉個例子, 比如: 一個班, 有幾個學生參加期末考試, 要計算考試的平均分. 我們來看看, 通常要怎麼做?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">考試成績
    <ul>
        <li v-for="stu in students">{{stu.name}} -- {{stu.score}}</li>
    </ul>

    <p>平均分: <label>{{getAvg()}}</label></p>
</div>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: "#app",
        data: {
            message:"班級考試平均分",
            students: [
                {name:"張三", score:90},
                {name:"lisi", score:100},
                {name:"wangwu", score:99},
                {name:"zhaoliu", score:89},
                {name:"liuqi", score:95}
            ]
        },
        methods: {
            getAvg() {
                let sum = 0;
                 for (let i = 0; i < this.students.length; i++) {
                     console.log(this.students[i].score);
                     let stu = this.students[i];
                     sum += stu.score;
                 }
                 console.log("平均分:" + sum/this.students.length);
                 return sum/this.students.length;
            }
        }
    })
</script>
</body>
</html>

我們定義了一組學生的成績. 然後將其顯示在頁面上, 然後通過方法getAvg計算平均分. 

3. Vue語法--計算屬性

 

 這裡我們在獲取平均分的時候, 使用的是{{getAve()}} 其實, 平均分我們理解更像是一個屬性, 而不是一個方法. 為了方便計算, vue給我們提供了一個computed屬性, 專門用來做計算. computed中定義的也是方法, 這個方法的方法名通常都定義為名詞. 我們來看一下使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">考試成績
    <ul>
        <li v-for="stu in students">{{stu.name}} -- {{stu.score}}</li>
    </ul>

    <p>平均分: <label>{{avg}}</label></p>
</div>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: "#app",
        data: {
            message:"班級考試平均分",
            students: [
                {name:"zhangsan", score:90},
                {name:"lisi", score:100},
                {name:"wangwu", score:99},
                {name:"zhaoliu", score:89},
                {name:"liuqi", score:95}
            ]
        },
        computed: {
            avg: function() {
                let sum = 0;
                for (let i = 0; i < this.students.length; i++) {
                    console.log(this.students[i].score);
                    let stu = this.students[i];
                    sum += stu.score;
                }
                console.log("平均分:" + sum/this.students.length);
                return sum/this.students.length;
            }
        },
        methods: {

        }
    })
</script>
</body>
</html>

這裡,增加了一個computed屬性, 裡面定義了avg方法, 沒錯, 本質還是方法, 但命名的時候, 將其命名為名詞.

眼尖的同學應該已經發現了, 這好像和methods方法一樣啊, 就是換了個名字. 那computed計算屬性和methods方法有什麼區別呢?

2. 計算屬性computed的快取功能

我們用案例來說明他們之間的區別. 

案例1. methods方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <p> Origin Message: {{message}}</p>
    <p>Mthod Message:{{getMessage()}}</p>
    <p>Mthod Grade:{{getGrade()}}</p>
    <p>Mthod Class:{{getClass()}}</p>
</div>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: "#app",
        data: {
            message:"班級考試平均分",
            className: "1班",
            gradeName:"一年級"
        },
        methods: {
            getGrade: function(){
                console.log("呼叫Grade計算")
                return "方法" + this.gradeName
            },
            getClass: function(){
                console.log("呼叫class計算")
                return "方法" + this.className
            },
            getMessage: function(){
                console.log("呼叫message計算")
                return "方法" + this.message
            }
        }
    })
</script>
</body>
</html>

 

3. Vue語法--計算屬性

 

 我們發現, 在修改一個屬性, 其他屬性都沒變化的情況下, 我們發現methods裡的方法都被執行了一遍

 案例2. computed計算屬性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <p> Origin Message: {{message}}</p>
    <p>Mthod Message:{{getMessage}}</p>
    <p>Mthod Grade:{{getGrade}}</p>
    <p>Mthod Class:{{getClass}}</p>
</div>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: "#app",
        data: {
            message:"班級考試平均分",
            className: "1班",
            gradeName:"一年級"
        },
        computed: {
            getGrade: function(){
                console.log("呼叫Grade計算")
                return "方法" + this.gradeName
            },
            getClass: function(){
                console.log("呼叫class計算")
                return "方法" + this.className
            },
            getMessage: function(){
                console.log("呼叫message計算")
                return "方法" + this.message
            }
        }
    })
</script>
</body>
</html>

控制檯輸出

 3. Vue語法--計算屬性

 我們發現, 當控制檯修改其中一個屬性值, 只有呼叫這個屬性的方法會重新執行

 

案例3:  再看一個computed快取的例子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">
    <p>呼叫方法</p>
    <p>{{getMes()}}</p>
    <p>{{getMes()}}</p>
    <p>{{getMes()}}</p>
    <p>{{getMes()}}</p>


    <p>呼叫計算屬性</p>
    <p>{{mes}}</p>
    <p>{{mes}}</p>
    <p>{{mes}}</p>
    <p>{{mes}}</p>

</div>
<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: "#app",
        data: {
            firstName: "Elon",
            lastName: "Musk"
        },
        computed: {
            mes: function(){
                console.log("呼叫計算屬性")
                return this.firstName + " " + this.lastName
            }
        },
        methods: {
            getMes: function(){
                console.log("呼叫method方法")
                return  this.firstName  + " " +  this.lastName
            }
        }
    })
</script>
</body>
</html>

這是兩種方式的呼叫, 但是結果都一樣, 都是列印輸出姓名, 計算屬性mes呼叫了四次, 方法getMes()也呼叫了四次, 我們來看看執行結果

3. Vue語法--計算屬性

 

 兩次列印的結果是一樣的, 但是呼叫getMes()呼叫了4次, 而mes計算屬性只計算了一次.

 

總結

  • methods方法和computed計算屬性,兩種方式的最終結果確實是完全相同
  • 不同的是計算屬性是基於它們的響應式依賴進行快取的。只在相關響應式依賴發生改變時它們才會重新求值,多次訪問getMessage 計算屬性會立即返回之前的計算結果,而不必再次執行函式。
  • methods方法,每當觸發重新渲染時,呼叫方法將總會再次執行函式。

所以,官網說,對於任何複雜邏輯,都應當使用計算屬性。

3. 計算屬性的getter和setter訪問器

問題: 我們發現, 在計算屬性和methods方法呼叫的是偶還有一點不同, 那就是呼叫方式不同. method方呼叫是{{getMessage()}}, 而計算屬性是{{getMessage}}, 我們上面不是說計算屬性中定義的也是方法麼? 為什麼不需要使用()呢? 下面來研究一下

還是這個案例, 我們來看看程式碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">{{message}} {{avg}}</div>

<script src="../js/vue.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            message: "計算平均分:",
            students: [
                {name:"zhangsan", score:90},
                {name:"lisi", score:100},
                {name:"wangwu", score:99},
                {name:"zhaoliu", score:89},
                {name:"liuqi", score:95}
            ]
        },
        computed: {
            avg: function() {
                let sum = 0;
                for (let i = 0; i < this.students.length; i++) {
                    console.log(this.students[i].score);
                    let stu = this.students[i];
                    sum += stu.score;
                }
                console.log("平均分:" + sum/this.students.length);
                return sum/this.students.length;
            }
          
        }
    });
</script>
</body>
</html>

 我們在計算平均分的時候, 是把avg當做一個屬性來對待的, 所以,呼叫的時候這麼寫{{avg}}, 而不是{{avg()}}. 但是我們定義的時候卻是給定義成方法了, 為什麼會這樣呢?

下面我們來研究computed完整的寫法, 研究完這個, 就知道為什麼這麼寫了. 

 

  • 其實計算屬性本身是定義為了一個屬性. 例如: 我們定義test, 通常我們定義屬性是這麼定義的
test: "這是一個屬性"
  • 在計算屬性裡, 屬性值是一個物件, 所以, 我們要這麼定義
computed: {
    test: {

    }
}
  • 物件的內部有兩個方法, 一個是get方法, 一個是set方法. 這時在get方法中return一個abc, 這是, 在頁面顯示的就應該是abc
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">{{message}} --- {{avg}} --- {{test}}</div>

<script src="../js/vue.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            message: "計算平均分:",
            students: [
                {name:"zhangsan", score:90},
                {name:"lisi", score:100},
                {name:"wangwu", score:99},
                {name:"zhaoliu", score:89},
                {name:"liuqi", score:95}
            ]
        },
        computed: {
            avg: function() {
                let sum = 0;
                for (let i = 0; i < this.students.length; i++) {
                    console.log(this.students[i].score);
                    let stu = this.students[i];
                    sum += stu.score;
                }
                console.log("平均分:" + sum/this.students.length);
                return sum/this.students.length;
            },
            test : {
                set: function(newValue) {
                    this.message = newValue;
                    console.log("呼叫setter")
                },
                get: function() {
                    return "abc" 
                }
            }
        }
    });
</script>
</body>
</html>

看看效果

3. Vue語法--計算屬性

確實列印輸出了abc

 

 

  • 因為有get方法和set方法, 所以, 我們可以修改test的值,  如下: 修改了app.test的值, 最終改變了message的值.

 3. Vue語法--計算屬性

 

  • 然而, 計算屬性通常只實現get方法, 而不實現set方法. 我們是計算後輸出, 而不允許北外不修改,  這時計算屬性就只剩下一個get方法, 最後我們將其簡寫, 去掉get, 就是我們通常看到的寫法
computed: {
    avg: function() {
        let sum = 0;
        for (let i = 0; i < this.students.length; i++) {
            console.log(this.students[i].score);
            let stu = this.students[i];
            sum += stu.score;
        }
        console.log("平均分:" + sum/this.students.length);
        return sum/this.students.length;
    },
    avg1 : function() {
            return "abc" 
        
    }
}

雖然寫法和method差不多. 但本質上, 計算屬性還是屬性, 所以, 和屬性的寫法是一樣的.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

as

 

相關文章