在上篇文章中,有與各位分享到 Vue 的語法,以及如何將實體 data 結合運算式並渲染至畫面。那如果遇上複雜的運算邏輯時,或是重複置入同樣的複雜運算式時,模板會變得難以維護。假設我們需要在不同的網頁中呈現「班級人數」時,就會在每個頁面中寫上相同的程式碼,那就可能讓我們在維護上增加遺忘的機率,而且在模板中插入了過於複雜的邏輯運算時,不僅造成程式碼混亂難以維護,也可能發生不可預期的危險。
那以下,我們就來和各位聊聊,該如何解決此問題吧!
當我們在開發專案時,有時會遇到明明同樣的東西,但我們卻寫了3次、4次、5次...甚至更多。這樣不僅讓我們花費更多時間,也導致在日後的維護上會更加的困難,這時候呢,我們就只需要將重複的部分提取出來並包裝成函式以便重複使用,必且放在 methods的屬性中。
<script>
export default {
data() {
return {
price: 500,
people: 3,
};
},
methods: {
iThome_2022() {
return this.price * this.people;
},
},
};
</script>
而在 methods 中,是需要使用 this 去存取 data 裡的屬性,並且在 HTML 中使用 methods 時需要加上小括號,或設計成帶有參數的方式去執行。
照上方的範例程式碼來看,我們已經將邏輯完成了,那接下來如果想讓他在網頁上呈現呢?就可以在模板裡,透過去呼叫 iThome_2022() 的方式去獲取我們要的金額 (price * people)
<template>
<div>
<p>價格:{{ price }}</p>
<p>人數:{{ people }}</p>
<p>金額為 {{ iThome_2022() }} 元</p>
</div>
</template>
網頁呈現結果:
那需要特別注意的是,在 Vue 的實體中,我們可以透過 this
來存取我們想要的實體。舉個例子,我們看回上方的範例程式碼,price 和 people 已經被我們放在 data 裡面了,但到了 methods 時,我們就需要在他們的前面加上 this 後才能存取他們。
值得一提的是,在 methods 裡面的內容其實是一個 function
,在我們需要使用時就可以呼叫他,所以在 <template>
中就需在他們的兩側加上小括號,就像這樣:iThome_2022()
,當然有必要時我們也可以加上參數傳過去。
除此之外,各位也需要注意一點,如果我們想在 Vue 實體中的另一個 methods 呼叫 iThome_2022()
時,就需要在前面加上 this
,那如果是想在 <template>
中呼叫就不需要囉!
Computed 與 methods 的寫法可說是一模一樣的,讓我們看看範例:
<script>
export default {
data() {
return {
price: 500,
people: 3,
};
},
computed: {
iThome_2022() {
return this.price * this.people;
},
},
};
</script>
<template>
<div>
<p>價格:{{ price }}</p>
<p>人數:{{ people }}</p>
<p>金額為 {{ iThome_2022 }} 元</p>
</div>
</template>
可以看得出來不一樣的地方只有 data 後面的 methods 與 computed,與 html 中少了小括號,但要注意的是,雖然差不多,但兩者的功能終究還是不同的,所以可不能相互改寫喔!讓我們把他們寫在一起看看:
<script>
export default {
data() {
return {
price: 500,
people: 3,
};
},
computed: {
iThome_2022_computed() {
console.log("computed");
return this.price * this.people;
},
},
methods: {
iThome_2022_methods() {
console.log("methods");
return this.price * this.people;
},
},
};
</script>
<template>
<div>
<p>價格:{{ price }}</p>
<p>人數:{{ people }}</p>
<p>金額為 {{ iThome_2022_computed }} 元</p>
<p>金額為 {{ iThome_2022_methods() }} 元</p>
</div>
</template>
寫完程式碼後,讓我們看看網頁的輸出結果:
那這時,如果我們將 <template>
裡稍作修改,將他們重複各寫兩次:
<template>
<div>
<p>價格:{{ price }}</p>
<p>人數:{{ people }}</p>
<hr />
<p>金額為 {{ iThome_2022_computed }} 元 (computed)</p>
<p>金額為 {{ iThome_2022_computed }} 元 (computed)</p>
<p>金額為 {{ iThome_2022_computed }} 元 (computed)</p>
<hr />
<p>金額為 {{ iThome_2022_methods() }} 元 (methods)</p>
<p>金額為 {{ iThome_2022_methods() }} 元 (methods)</p>
<p>金額為 {{ iThome_2022_methods() }} 元 (methods)</p>
</div>
</template>
可以看見網頁上所呈現的 computed 與 methods 都是各三行
那由於我們在上方兩個函式裡都寫了 console.log(),就來看看主控台 console :
可以看到 methods 的前面多了一個 3,代表iThome_2022_methods()
執行了三次。
而 computed 前面沒有數字,代表 subtotalComputed
只執行了一次。
這是為什麼呢?
因為 computed
的屬性是會將計算過後的結果暫存,後續如果也沒有更新的話,computed 也就不會重複執行。如果同樣都是重複計算的話,使用 computed 來處理會比 methods 來得好,但要特別注意的是,computed 的 function 是無法使用參數的,若有需要帶入參數的情況時,建議用 mehtods 來處理會比較好喔!
computed :
1.計算後會將結果暫存。
2.如果暫存後的資料後續沒有變動,就不會重複執行。
3.擅長執行重複計算,可節省較多效能。
4.無法帶入參數。
Methods :
1.如是在 HTML 裡被使用多次,就會執行多次。
2.可帶入參數。
最後,就讓我們來做一個小實作結束這回合吧。
相信各位再求學階段時,都有量過身高體重吧,但在算 BMI 時,甚麼平方算完再除,是不是很麻煩呢,那就讓我們來做一個簡易的 BMI 計算機吧:
首先,我們再網頁中放入兩個 input 輸入框及一個 button:
<template>
<div>
<p>BMI 算法:體重除以身高的平方<br /></p>
<div>身高 <input type="text" /> 公分</div>
<div>體重 <input type="text" /> 公斤</div>
</div>
<button style="margin: 15px">開始計算</button>
<br />
<input type="text" readonly />
</template>
可以看到以上程式碼,我們將身高體重的 input 的 type 設定成 "text",讓使用者可以輸入自己的身高和體重,輸入後便可按下開始計算
的 button,計算的結果就會呈現在我們的 input 裡,那為甚麼我們要在這邊用上 input 呢?其實是因為可以方便我們直接加上 v-model 去計算數值,readonly
則是設定成唯讀。
不懂 v-model 沒關係,後續會專門寫一篇做介紹,簡單來說就是讓我們的資料可以雙向綁定,計算完後直接呈現在上面,而目前可以用 v-model 的只有 input、select、checkbox
再看看我們的網頁:
那只有網頁沒有功能也不行,所以接下來我們來做功能部分:
首先,我們需要先在 button 的部分加入事件綁定:@click
(有關事件綁定:v-on 後續也會與各位做介紹),讓我們點擊按鈕後就可進行函式的運算
<button style="margin: 15px" @click="BMI()">開始計算</button>
那計算後要如何抓取使用者輸入的值呢,就需要用到v-model
了:
<div>身高 <input type="text" v-model="height" /> 公分</div>
<div>體重 <input type="text" v-model="weight" /> 公斤</div>
像這樣,就可以在使用者輸入身高和體重後,將數值暫存
接下來就進行運算,bmi 的算法是體重(公斤)除以身高(公尺)的平方
,轉換成程式語言後就是:weight / (height*height)
也因台灣人常用的身高單位是公分,但 bmi 的身高單位是公尺,所以改寫一下:weight / ((height / 100 )*(height / 100))
(1公尺 = 100公分)
我們也為了避免計算過後的小數點太長,所以只取他的小數點後3位就好:(weight / ((height / 100 )*(height / 100))).toFixed(3)
(toFixed:四捨五入,括號裡輸入想取到小數點第幾位)
最後,我們可以透過 parseFloat 來解析數值:parseFloat((weight / ((height / 100 )*(height / 100)))).toFixed(3)
ok,計算完成了,但要顯示在哪裡呢?就是我們的唯讀 input 對吧,那這時候又需要呼叫 v-model
了,v-model 是用來資料雙向綁定的,那除了可以抓取使用者輸入的值,當然也能把計算後的值馬上呈現在網頁拉,就像這樣:
<input type="text" v-model="bmiValue" readonly />
再來我們要進入 <script>
的環節拉了
首先,先在 data 中宣告 bmiValue
的屬性,讓我們可以在 button 點擊後馬上呈現:
data() {
return {
bmiValue: "",
};
},
運算將他寫在 methods
裡,這邊要先跟各位說明一下我們設計程式的邏輯:
當使用者輸入身高及體重後,點擊開始計算的按鈕,結果即會呈現在 input 的欄位
所以,我們的運算式就會寫在 BMI()
這個函式裡,並讓計算出的結果輸出到 bmiValue
中,而 input 的v-model
則會幫助我們將計算結果呈現於網頁上:
methods: {
BMI() {
this.bmiValue = Number.parseFloat(
Number(this.weight) /
Number(Number(this.height / 100) * Number(this.height / 100))
).toFixed(3);
},
},
就像這樣,那需要注意的是,為了去解析數值,我們在有計算的部分都要加上一個 Number
,且為了讓 Vue 知道我們想要指定 html 的 v-model
,所以在呼叫時需要在前面加上 this
。
最後來看看我們的網頁:
恭喜各位,那我們的 bmi 計算器的小小實做就成功拉。
<template>
<div>
<p>BMI 算法:體重除以身高的平方<br /></p>
<div>身高 <input type="text" v-model="height" /> 公分</div>
<div>體重 <input type="text" v-model="weight" /> 公斤</div>
</div>
<button style="margin: 15px" @click="BMI()">開始計算</button>
<br />
<input type="text" v-model="bmiValue" readonly />
</template>
<script>
export default {
data() {
return {
bmiValue: "",
};
},
methods: {
BMI() {
this.bmiValue = Number.parseFloat(
Number(this.weight) /
Number(Number(this.height / 100) * Number(this.height / 100))
).toFixed(3);
},
},
};
</script>
那我們今天對於 methods 及 computed 的介紹就到這裡結束拉
希望今天實作的講解是淺顯易懂的,讓看過的人都可以學會!謝謝大家<3