Vue options api
===
###### tags: `vue筆記`
## methods 方法
### methods觸發
methods 的觸發方法有很多種:
1. 一般指令:click,change....像是下方範例。
```html
<button type="button" @click="trigger('Click Methods')">點擊觸發</button>
```
2. 其它 options api,意思是其他 methods 互相呼叫。
```html
<button type="button" @click="callOtherMethod">呼叫另一個 methods</button>
```
以這個範例是,上面的按鈕先觸發一個 `function` ,再由該 `function` 觸發另外一個 `function`。
```jsx
methods: {
trigger(name) {
console.log(name, '此事件被觸發了')
},
callOtherMethod() {
this.trigger('由 callOtherMethod 觸發')
},
},
```
3. 生命週期觸發:created,mounted,這就是Vue本身的生命步驟了,當到了該步驟就會觸發。
```jsx
created() {
this.trigger('由生命週期觸發');
},
```
#### ***注意:***
撰寫 options api 的函式,不要使用箭頭函式,因為 options api 大量使用 `this`,使用箭頭函式會無法取得 `this` 資料!
### Dom事件傳參數
在寫普通Js時,經常用到 `e.target` 等,在 Vue 要用這個時,要在該Dom事件中傳入 `$event` 參數。
```html
<button type="button" @click="methodParameter($event)">參數傳入</button>
```
這樣在該函式就可以收到Dom事件相關資料,也就可以取得像是dataset等資料。
```jsx
methodParameter(e) {
console.log(e.target.dateset)
},
```
### 搭配 v-for 傳入參數
搭配v-for是非常常用的作法,其實跟原生 js 搭配 `data-` 屬性的概念有點相似,以下就用範例說明:
```html
<template v-for="product in products" :key="product.id">
<div @click="openProductDetail(product)">
<p>{{product.title}}</p>
<p>{{product.origin_price}}<p>
</div>
</template>
```
`v-for="product in products"` 前面的 product 就是自定義的每一筆陣列資料,只要把該值當作參數帶入即可做後續操作,像是 push 或是 篩選 等等。
***
## computed運算
computed 跟其他幾個 method 不同,其他可以直接操作,但是 computed 大部分是讀取資料,計算新的結果再回到畫面上。雖然說是這樣說,但是大部分感覺跟 methods 有點像,不一樣的是裡面會是 return,而這個 return 值就可以直接用來呈現在畫面中:
```jsx
const App = {
computed:{
total(){
let num = 0;
this.cart.forEach((item)=>{
num += item.price
})
return num;
}
}
};
```
常見的購物車計算總值,計算後可以當作他是一般data一樣。
```html
{{total}}
```
*一定要 return 東西,否則會出錯。
*另外要注意說 computed 只要裡面資料更新,就會調用並回傳,所以當`this.carts` 中新增資料,該函式自動會更新。
### 搭配 filter 可以做到 search
search 是常見的網頁功能,所以一定要學會!而使用 computed 可以輕鬆達成,首先給input先綁定一個`v-model="search"` 字串資料,我們的做法就是當搜尋時,把符合需求的值送進 `filterProducts` 陣列,然後下面的 `v-for` 會呈現 `filterProducts` 陣列的值:
```html
<input type="search" v-model="search">
<ul>
<li v-for="item in filterProducts">
{{ item.name }} / {{ item.price }}
</li>
</ul>
```
所以在 computed 寫一個 `filterProducts()` ,塞選出 item 的 name 屬性 match 搜尋的值:
```jsx
const App = {
computed:{
filterProducts(){
return this.products.filter(item=>{
return item.name.match(this.search);
})
}
}
};
```
---
## computed 運算之Getter,Setter
computed 把 data 中資料取出放到函式運算後取去渲染畫面,這叫做 Getter 。
computed 還有另外一個 setter ,是把資料重新調整後送回 data 中。
如果要加入 Getter 和 Setter ,需要把 computed 修改成物件形式:
```jsx
const App = {
computed:{
total:{
get(){
let total = 0;
this.carts.forEach(item=>{
total += item.price
})
return total
}
}
}
};
```
改成上面這樣 get() ,依舊可以運作,這時候我們可以新增一個 input ,嘗試操作該函式中的total值 `@click="total = num"` :
```html
<input type="number" v-model.number="num">
<button type="button" @click="total = num">更新</button>
total 的值:{{ total }}
sum 的值:{{ sum }}
```
這時候其實不會有任何動作,因為computed一開始只有讀取功能,我們可以來寫 `set()` ,但要記得 `set(參數)`,要帶入一個參數:
```jsx
const App = {
computed:{
total:{
get(){
let total = 0;
this.carts.forEach(item=>{
total += item.price
})
return this.sum || total
},
set(val){
this.sum = val * 0.8
}
}
}
};
```
另外可以看到 get() 中,`return this.sum || total` 改變了,是因為可以設定如果有 set 產生新值,就用新值,不然用舊值。
---
## Watch監聽
watch 跟 computed 有點像, computed 是把 data 值取出重新運算在渲染,而 watch 是 監聽單一data 值,而該值有變化,就會觸發事件。
*注意 watch 不會產生新值,而是修改 data 內容,而 data 有變化自然畫面也會跟著變化。
以下範例是當 input 值變化,就會呼叫 watch 透過 calMoney() 去判定並改變 data 中的 result:
```html
<input type="number" id="name" v-model.number="money">
<P>result: {{ result }}</P>
```
watch 物件中把要監聽的變數名稱建立成函式,而函式帶入兩個參數,第一個是改變後的新值,第二個是上一次變化的舊值,記得只要值改變,就一定會呼叫:
```jsx
const App = {
data() {
return {
money:0,
result: '',
}
},
watch:{
calMoney( newValue , oldValue ){
if(newValue > 10){
this.result = `數字大於10`
}else if(newValue < 10){
this.result = `數字小於10`
}
},
},
};
```
### 與computed有什麼不同?
- watch:只能監聽一個值,但是能在函式中同時操作很多data資料。如果需要監聽多個值,就要重複寫很多個函式。
而且watch一開始打開頁面不會執行任何動作,因為本身資料沒有改變。
- conputed:一次監聽data多筆資料,但是只會 return 出一個值,所以產出的結果就是那個值。
### watch 深層監聽
前面 watch 監聽的都是一個單一值,watch也能監聽物件,但是要改成深層監聽的方式
```html
<label for="productName">商品名稱</label>
<input type="text" v-model="product.name">
<label for="productPrice">商品價格</label>
<input type="number" v-model.number="product.price">
<label><input type="checkbox" v-model="product.vegan"> 素食</label>
<p>result : {{ result }}</p>
```
上面範例是input各自配對到物件的每個屬性,改變該值自然就改變了物件。
```jsx
const App = {
data() {
return {
product: {
name: '蛋餅',
price: 30,
vegan: false
},
result: '',
}
},
watch:{
product:{
deep:true,
handler(newValue , oldValue){
this.result = `總共買了${this.product.name},花了${this.product.price}。`
}
}
},
};
```
這裡的 product 要改成物件寫法,同時裡面要加上 deep:true 的屬性值,最後加上一個控制器`handler(newValue , oldValue)` ,控制器函式就跟原本的 watch 差不多了,這時候兩個參數newValue , oldValue,分別代表的是新舊product物件,那就能用該值做事情摟~
---
## Vue的元件命週期
一個網頁有很多Vue子元件,包含像是header,sideNav,main等等,當切換頁面時自然就會讓有些元件卸載再重新生成,那就會觸發不同生命週期。
- beforeCreat:資料建立前
- created:資料已經建立完成
- beforeMount:準備把 HTML 結構掛載到畫面上,但還沒掛載上去。
- mounted:已經把 HTML 結構掛載上去,通常到這裡代表畫面已經完成,所以會停在這裡,除非有任何資料變更,那才會進到下一步。
*如果需要針對生成的HTML做操作,JS要下在 mounted 之後,因為在mounted 之前HTML還沒生成。
- beforeUpdate、updated:很清楚就是更新資料前後。
- beforeUnmount、unmounted:最後卸載前和卸載後的狀況,在這兩個階段其實都還能抓到資料喔。
***
## v-if 和 v-show
v-if 是判定是否存在,所以只要關閉再啟動,就會重新抓取資料,如果資料變更後沒做存取,那資料會被重置。
v-show是判定用 `display:none` 是否顯示,所以資料還在,只是隱形了。
但一般常會使用 v-if 來做開發,較能正確使用生命週期,這時候如果要保留資料狀態,就要使用 `keep-alive` 標籤 ,只要在外層包上 `keep-alive` ,
```html
<keep-alive>
<child v-if="isShowing"></child>
</keep-alive>
```
當關閉 v-if 時,生命週期會進入 `deactivated()` ,而再次啟動時,會進入 `activated()` 同時上次變更的資料狀態還會保留著。