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()` 同時上次變更的資料狀態還會保留著。