一. 計算屬性
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計算平均分.
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL0cDNxIDN1YzNx0iM1MzN1kzM2ADMyIDMxIDMy0iNxkzN4ETMvwlMwEjMwIzLcZTM5cDOxEzLcd2bsJ2Lc12bj5ycn9Gbi52YuAjMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
這裡我們在擷取平均分的時候, 使用的是{{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>
我們發現, 在修改一個屬性, 其他屬性都沒變化的情況下, 我們發現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: 再看一個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()也調用了四次, 我們來看看運作結果
兩次列印的結果是一樣的, 但是調用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>
看看效果
确實列印輸出了abc
- 因為有get方法和set方法, 是以, 我們可以修改test的值, 如下: 修改了app.test的值, 最終改變了message的值.
- 然而, 計算屬性通常隻實作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